blob: 701880236ee3a71ec90c13ca1f7284a36c5d18fa [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#if V8_TARGET_ARCH_X87
6
7#include "src/code-factory.h"
8#include "src/codegen.h"
9#include "src/deoptimizer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/full-codegen/full-codegen.h"
11#include "src/x87/frames-x87.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012
13namespace v8 {
14namespace internal {
15
16
17#define __ ACCESS_MASM(masm)
18
19
20void Builtins::Generate_Adaptor(MacroAssembler* masm,
21 CFunctionId id,
22 BuiltinExtraArguments extra_args) {
23 // ----------- S t a t e -------------
24 // -- eax : number of arguments excluding receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025 // -- edi : target
26 // -- edx : new.target
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027 // -- esp[0] : return address
28 // -- esp[4] : last argument
29 // -- ...
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 // -- esp[4 * argc] : first argument
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 // -- esp[4 * (argc +1)] : receiver
32 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033 __ AssertFunction(edi);
34
35 // Make sure we operate in the context of the called function (for example
36 // ConstructStubs implemented in C++ will be run in the context of the caller
37 // instead of the callee, due to the way that [[Construct]] is defined for
38 // ordinary functions).
39 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040
41 // Insert extra arguments.
42 int num_extra_args = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 if (extra_args != BuiltinExtraArguments::kNone) {
44 __ PopReturnAddressTo(ecx);
45 if (extra_args & BuiltinExtraArguments::kTarget) {
46 ++num_extra_args;
47 __ Push(edi);
48 }
49 if (extra_args & BuiltinExtraArguments::kNewTarget) {
50 ++num_extra_args;
51 __ Push(edx);
52 }
53 __ PushReturnAddressFrom(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 }
55
56 // JumpToExternalReference expects eax to contain the number of arguments
57 // including the receiver and the extra arguments.
58 __ add(eax, Immediate(num_extra_args + 1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
61}
62
Ben Murdoch097c5b22016-05-18 11:27:45 +010063static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
64 Runtime::FunctionId function_id) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 // ----------- S t a t e -------------
Ben Murdoch097c5b22016-05-18 11:27:45 +010066 // -- eax : argument count (preserved for callee)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067 // -- edx : new target (preserved for callee)
68 // -- edi : target function (preserved for callee)
69 // -----------------------------------
Ben Murdoch097c5b22016-05-18 11:27:45 +010070 {
71 FrameScope scope(masm, StackFrame::INTERNAL);
72 // Push the number of arguments to the callee.
73 __ SmiTag(eax);
74 __ push(eax);
75 // Push a copy of the target function and the new target.
76 __ push(edi);
77 __ push(edx);
78 // Function is also the parameter to the runtime call.
79 __ push(edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080
Ben Murdoch097c5b22016-05-18 11:27:45 +010081 __ CallRuntime(function_id, 1);
82 __ mov(ebx, eax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083
Ben Murdoch097c5b22016-05-18 11:27:45 +010084 // Restore target function and new target.
85 __ pop(edx);
86 __ pop(edi);
87 __ pop(eax);
88 __ SmiUntag(eax);
89 }
90
91 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
92 __ jmp(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093}
94
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010096 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
97 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset));
98 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
99 __ jmp(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100}
101
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000102void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
103 // Checking whether the queued function is ready for install is optional,
104 // since we come across interrupts and stack checks elsewhere. However,
105 // not checking may delay installing ready functions, and always checking
106 // would be quite expensive. A good compromise is to first check against
107 // stack limit as a cue for an interrupt signal.
108 Label ok;
109 ExternalReference stack_limit =
110 ExternalReference::address_of_stack_limit(masm->isolate());
111 __ cmp(esp, Operand::StaticVariable(stack_limit));
112 __ j(above_equal, &ok, Label::kNear);
113
Ben Murdoch097c5b22016-05-18 11:27:45 +0100114 GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000115
116 __ bind(&ok);
117 GenerateTailCallToSharedCode(masm);
118}
119
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120static void Generate_JSConstructStubHelper(MacroAssembler* masm,
121 bool is_api_function,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100122 bool create_implicit_receiver,
123 bool check_derived_construct) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000124 // ----------- S t a t e -------------
125 // -- eax: number of arguments
Ben Murdochda12d292016-06-02 14:46:10 +0100126 // -- esi: context
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 // -- edi: constructor function
128 // -- ebx: allocation site or undefined
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 // -- edx: new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 // -----------------------------------
131
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 // Enter a construct frame.
133 {
134 FrameScope scope(masm, StackFrame::CONSTRUCT);
135
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136 // Preserve the incoming parameters on the stack.
137 __ AssertUndefinedOrAllocationSite(ebx);
Ben Murdochda12d292016-06-02 14:46:10 +0100138 __ push(esi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 __ push(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140 __ SmiTag(eax);
141 __ push(eax);
142
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 if (create_implicit_receiver) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100144 // Allocate the new receiver object.
145 __ Push(edi);
146 __ Push(edx);
147 FastNewObjectStub stub(masm->isolate());
148 __ CallStub(&stub);
149 __ mov(ebx, eax);
150 __ Pop(edx);
151 __ Pop(edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152
Ben Murdoch097c5b22016-05-18 11:27:45 +0100153 // ----------- S t a t e -------------
154 // -- edi: constructor function
155 // -- ebx: newly allocated object
156 // -- edx: new target
157 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158
159 // Retrieve smi-tagged arguments count from the stack.
160 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 }
162
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163 __ SmiUntag(eax);
164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 if (create_implicit_receiver) {
166 // Push the allocated receiver to the stack. We need two copies
167 // because we may have to return the original one and the calling
168 // conventions dictate that the called function pops the receiver.
169 __ push(ebx);
170 __ push(ebx);
171 } else {
172 __ PushRoot(Heap::kTheHoleValueRootIndex);
173 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174
175 // Set up pointer to last argument.
176 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
177
178 // Copy arguments and receiver to the expression stack.
179 Label loop, entry;
180 __ mov(ecx, eax);
181 __ jmp(&entry);
182 __ bind(&loop);
183 __ push(Operand(ebx, ecx, times_4, 0));
184 __ bind(&entry);
185 __ dec(ecx);
186 __ j(greater_equal, &loop);
187
188 // Call the function.
Ben Murdochc5610432016-08-08 18:44:38 +0100189 ParameterCount actual(eax);
190 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION,
191 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192
193 // Store offset of return address for deoptimizer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194 if (create_implicit_receiver && !is_api_function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
196 }
197
198 // Restore context from the frame.
Ben Murdochda12d292016-06-02 14:46:10 +0100199 __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 if (create_implicit_receiver) {
202 // If the result is an object (in the ECMA sense), we should get rid
203 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
204 // on page 74.
205 Label use_receiver, exit;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000206
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 // If the result is a smi, it is *not* an object in the ECMA sense.
208 __ JumpIfSmi(eax, &use_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210 // If the type of the result (stored in its map) is less than
211 // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
212 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
213 __ j(above_equal, &exit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 // Throw away the result of the constructor invocation and use the
216 // on-stack receiver as the result.
217 __ bind(&use_receiver);
218 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000220 // Restore the arguments count and leave the construct frame. The
221 // arguments count is stored below the receiver.
222 __ bind(&exit);
223 __ mov(ebx, Operand(esp, 1 * kPointerSize));
224 } else {
225 __ mov(ebx, Operand(esp, 0));
226 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227
228 // Leave construct frame.
229 }
230
Ben Murdoch097c5b22016-05-18 11:27:45 +0100231 // ES6 9.2.2. Step 13+
232 // Check that the result is not a Smi, indicating that the constructor result
233 // from a derived class is neither undefined nor an Object.
234 if (check_derived_construct) {
235 Label dont_throw;
236 __ JumpIfNotSmi(eax, &dont_throw);
237 {
238 FrameScope scope(masm, StackFrame::INTERNAL);
239 __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
240 }
241 __ bind(&dont_throw);
242 }
243
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 // Remove caller arguments from the stack and return.
245 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
246 __ pop(ecx);
247 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
248 __ push(ecx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 if (create_implicit_receiver) {
250 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
251 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 __ ret(0);
253}
254
255
256void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100257 Generate_JSConstructStubHelper(masm, false, true, false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000258}
259
260
261void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100262 Generate_JSConstructStubHelper(masm, true, false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263}
264
265
266void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100267 Generate_JSConstructStubHelper(masm, false, false, false);
268}
269
270
271void Builtins::Generate_JSBuiltinsConstructStubForDerived(
272 MacroAssembler* masm) {
273 Generate_JSConstructStubHelper(masm, false, false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000274}
275
276
277void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
278 FrameScope scope(masm, StackFrame::INTERNAL);
279 __ push(edi);
280 __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
281}
282
283
284enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
285
286
287// Clobbers ecx, edx, edi; preserves all other registers.
288static void Generate_CheckStackOverflow(MacroAssembler* masm,
289 IsTagged eax_is_tagged) {
290 // eax : the number of items to be pushed to the stack
291 //
292 // Check the stack for overflow. We are not trying to catch
293 // interruptions (e.g. debug break and preemption) here, so the "real stack
294 // limit" is checked.
295 Label okay;
296 ExternalReference real_stack_limit =
297 ExternalReference::address_of_real_stack_limit(masm->isolate());
298 __ mov(edi, Operand::StaticVariable(real_stack_limit));
299 // Make ecx the space we have left. The stack might already be overflowed
300 // here which will cause ecx to become negative.
301 __ mov(ecx, esp);
302 __ sub(ecx, edi);
303 // Make edx the space we need for the array when it is unrolled onto the
304 // stack.
305 __ mov(edx, eax);
306 int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
307 __ shl(edx, kPointerSizeLog2 - smi_tag);
308 // Check if the arguments will overflow the stack.
309 __ cmp(ecx, edx);
310 __ j(greater, &okay); // Signed comparison.
311
312 // Out of stack space.
313 __ CallRuntime(Runtime::kThrowStackOverflow);
314
315 __ bind(&okay);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316}
317
318
319static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
320 bool is_construct) {
321 ProfileEntryHookStub::MaybeCallEntryHook(masm);
322
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000323 {
324 FrameScope scope(masm, StackFrame::INTERNAL);
325
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000326 // Setup the context (we need to use the caller context from the isolate).
327 ExternalReference context_address(Isolate::kContextAddress,
328 masm->isolate());
329 __ mov(esi, Operand::StaticVariable(context_address));
330
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000331 // Load the previous frame pointer (ebx) to access C arguments
332 __ mov(ebx, Operand(ebp, 0));
333
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334 // Push the function and the receiver onto the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335 __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000336 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
337
338 // Load the number of arguments and setup pointer to the arguments.
339 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
340 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
341
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 // Check if we have enough stack space to push all arguments.
343 // Expects argument count in eax. Clobbers ecx, edx, edi.
344 Generate_CheckStackOverflow(masm, kEaxIsUntaggedInt);
345
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346 // Copy arguments to the stack in a loop.
347 Label loop, entry;
348 __ Move(ecx, Immediate(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000349 __ jmp(&entry, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350 __ bind(&loop);
351 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
352 __ push(Operand(edx, 0)); // dereference handle
353 __ inc(ecx);
354 __ bind(&entry);
355 __ cmp(ecx, eax);
356 __ j(not_equal, &loop);
357
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 // Load the previous frame pointer (ebx) to access C arguments
359 __ mov(ebx, Operand(ebp, 0));
360
361 // Get the new.target and function from the frame.
362 __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset));
363 __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000364
365 // Invoke the code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 Handle<Code> builtin = is_construct
367 ? masm->isolate()->builtins()->Construct()
368 : masm->isolate()->builtins()->Call();
369 __ Call(builtin, RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000370
371 // Exit the internal frame. Notice that this also removes the empty.
372 // context and the function left on the stack by the code
373 // invocation.
374 }
375 __ ret(kPointerSize); // Remove receiver.
376}
377
378
379void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
380 Generate_JSEntryTrampolineHelper(masm, false);
381}
382
383
384void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
385 Generate_JSEntryTrampolineHelper(masm, true);
386}
387
Ben Murdochc5610432016-08-08 18:44:38 +0100388// static
389void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
390 // ----------- S t a t e -------------
391 // -- eax : the value to pass to the generator
392 // -- ebx : the JSGeneratorObject to resume
393 // -- edx : the resume mode (tagged)
394 // -- esp[0] : return address
395 // -----------------------------------
396 __ AssertGeneratorObject(ebx);
397
398 // Store input value into generator object.
399 __ mov(FieldOperand(ebx, JSGeneratorObject::kInputOffset), eax);
400 __ RecordWriteField(ebx, JSGeneratorObject::kInputOffset, eax, ecx,
401 kDontSaveFPRegs);
402
403 // Store resume mode into generator object.
404 __ mov(FieldOperand(ebx, JSGeneratorObject::kResumeModeOffset), edx);
405
406 // Load suspended function and context.
407 __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset));
408 __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
409
410 // Flood function if we are stepping.
411 Label skip_flooding;
412 ExternalReference step_in_enabled =
413 ExternalReference::debug_step_in_enabled_address(masm->isolate());
414 __ cmpb(Operand::StaticVariable(step_in_enabled), Immediate(0));
415 __ j(equal, &skip_flooding);
416 {
417 FrameScope scope(masm, StackFrame::INTERNAL);
418 __ Push(ebx);
419 __ Push(edx);
420 __ Push(edi);
421 __ CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
422 __ Pop(edx);
423 __ Pop(ebx);
424 __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
425 }
426 __ bind(&skip_flooding);
427
428 // Pop return address.
429 __ PopReturnAddressTo(eax);
430
431 // Push receiver.
432 __ Push(FieldOperand(ebx, JSGeneratorObject::kReceiverOffset));
433
434 // ----------- S t a t e -------------
435 // -- eax : return address
436 // -- ebx : the JSGeneratorObject to resume
437 // -- edx : the resume mode (tagged)
438 // -- edi : generator function
439 // -- esi : generator context
440 // -- esp[0] : generator receiver
441 // -----------------------------------
442
443 // Push holes for arguments to generator function. Since the parser forced
444 // context allocation for any variables in generators, the actual argument
445 // values have already been copied into the context and these dummy values
446 // will never be used.
447 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
448 __ mov(ecx,
449 FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset));
450 {
451 Label done_loop, loop;
452 __ bind(&loop);
453 __ sub(ecx, Immediate(Smi::FromInt(1)));
454 __ j(carry, &done_loop, Label::kNear);
455 __ PushRoot(Heap::kTheHoleValueRootIndex);
456 __ jmp(&loop);
457 __ bind(&done_loop);
458 }
459
460 // Dispatch on the kind of generator object.
461 Label old_generator;
462 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
463 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kFunctionDataOffset));
464 __ CmpObjectType(ecx, BYTECODE_ARRAY_TYPE, ecx);
465 __ j(not_equal, &old_generator);
466
467 // New-style (ignition/turbofan) generator object
468 {
469 __ PushReturnAddressFrom(eax);
470 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
471 __ mov(eax,
472 FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset));
473 // We abuse new.target both to indicate that this is a resume call and to
474 // pass in the generator object. In ordinary calls, new.target is always
475 // undefined because generator functions are non-constructable.
476 __ mov(edx, ebx);
477 __ jmp(FieldOperand(edi, JSFunction::kCodeEntryOffset));
478 }
479
480 // Old-style (full-codegen) generator object
481 __ bind(&old_generator);
482 {
483 // Enter a new JavaScript frame, and initialize its slots as they were when
484 // the generator was suspended.
485 FrameScope scope(masm, StackFrame::MANUAL);
486 __ PushReturnAddressFrom(eax); // Return address.
487 __ Push(ebp); // Caller's frame pointer.
488 __ Move(ebp, esp);
489 __ Push(esi); // Callee's context.
490 __ Push(edi); // Callee's JS Function.
491
492 // Restore the operand stack.
493 __ mov(eax, FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset));
494 {
495 Label done_loop, loop;
496 __ Move(ecx, Smi::FromInt(0));
497 __ bind(&loop);
498 __ cmp(ecx, FieldOperand(eax, FixedArray::kLengthOffset));
499 __ j(equal, &done_loop, Label::kNear);
500 __ Push(FieldOperand(eax, ecx, times_half_pointer_size,
501 FixedArray::kHeaderSize));
502 __ add(ecx, Immediate(Smi::FromInt(1)));
503 __ jmp(&loop);
504 __ bind(&done_loop);
505 }
506
507 // Reset operand stack so we don't leak.
508 __ mov(FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset),
509 Immediate(masm->isolate()->factory()->empty_fixed_array()));
510
511 // Resume the generator function at the continuation.
512 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
513 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
514 __ mov(ecx, FieldOperand(ebx, JSGeneratorObject::kContinuationOffset));
515 __ SmiUntag(ecx);
516 __ lea(edx, FieldOperand(edx, ecx, times_1, Code::kHeaderSize));
517 __ mov(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
518 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
519 __ mov(eax, ebx); // Continuation expects generator object in eax.
520 __ jmp(edx);
521 }
522}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000523
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000524// Generate code for entering a JS function with the interpreter.
525// On entry to the function the receiver and arguments have been pushed on the
526// stack left to right. The actual argument count matches the formal parameter
527// count expected by the function.
528//
529// The live registers are:
530// o edi: the JS function object being called
531// o edx: the new target
532// o esi: our context
533// o ebp: the caller's frame pointer
534// o esp: stack pointer (pointing to return address)
535//
Ben Murdoch097c5b22016-05-18 11:27:45 +0100536// The function builds an interpreter frame. See InterpreterFrameConstants in
537// frames.h for its layout.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
Ben Murdochc5610432016-08-08 18:44:38 +0100539 ProfileEntryHookStub::MaybeCallEntryHook(masm);
540
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541 // Open a frame scope to indicate that there is a frame on the stack. The
542 // MANUAL indicates that the scope shouldn't actually generate code to set up
543 // the frame (that is done below).
544 FrameScope frame_scope(masm, StackFrame::MANUAL);
545 __ push(ebp); // Caller's frame pointer.
546 __ mov(ebp, esp);
547 __ push(esi); // Callee's context.
548 __ push(edi); // Callee's JS function.
549 __ push(edx); // Callee's new target.
550
Ben Murdochc5610432016-08-08 18:44:38 +0100551 // Get the bytecode array from the function object (or from the DebugInfo if
552 // it is present) and load it into kInterpreterBytecodeArrayRegister.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000553 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100554 Label load_debug_bytecode_array, bytecode_array_loaded;
555 __ cmp(FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset),
556 Immediate(DebugInfo::uninitialized()));
557 __ j(not_equal, &load_debug_bytecode_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000558 __ mov(kInterpreterBytecodeArrayRegister,
559 FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100560 __ bind(&bytecode_array_loaded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000561
Ben Murdochc5610432016-08-08 18:44:38 +0100562 // Check function data field is actually a BytecodeArray object.
563 Label bytecode_array_not_present;
564 __ CompareRoot(kInterpreterBytecodeArrayRegister,
565 Heap::kUndefinedValueRootIndex);
566 __ j(equal, &bytecode_array_not_present);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 if (FLAG_debug_code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000568 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
569 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
570 eax);
571 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
572 }
573
Ben Murdoch097c5b22016-05-18 11:27:45 +0100574 // Push bytecode array.
575 __ push(kInterpreterBytecodeArrayRegister);
Ben Murdochc5610432016-08-08 18:44:38 +0100576 // Push Smi tagged initial bytecode array offset.
577 __ push(Immediate(Smi::FromInt(BytecodeArray::kHeaderSize - kHeapObjectTag)));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100578
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 // Allocate the local and temporary register file on the stack.
580 {
581 // Load frame size from the BytecodeArray object.
582 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
583 BytecodeArray::kFrameSizeOffset));
584
585 // Do a stack check to ensure we don't go over the limit.
586 Label ok;
587 __ mov(ecx, esp);
588 __ sub(ecx, ebx);
589 ExternalReference stack_limit =
590 ExternalReference::address_of_real_stack_limit(masm->isolate());
591 __ cmp(ecx, Operand::StaticVariable(stack_limit));
592 __ j(above_equal, &ok);
593 __ CallRuntime(Runtime::kThrowStackOverflow);
594 __ bind(&ok);
595
596 // If ok, push undefined as the initial value for all register file entries.
597 Label loop_header;
598 Label loop_check;
599 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
600 __ jmp(&loop_check);
601 __ bind(&loop_header);
602 // TODO(rmcilroy): Consider doing more than one push per loop iteration.
603 __ push(eax);
604 // Continue loop if not done.
605 __ bind(&loop_check);
606 __ sub(ebx, Immediate(kPointerSize));
607 __ j(greater_equal, &loop_header);
608 }
609
Ben Murdochc5610432016-08-08 18:44:38 +0100610 // Load accumulator, bytecode offset and dispatch table into registers.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000611 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 __ mov(kInterpreterBytecodeOffsetRegister,
613 Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
Ben Murdochc5610432016-08-08 18:44:38 +0100614 __ mov(kInterpreterDispatchTableRegister,
615 Immediate(ExternalReference::interpreter_dispatch_table_address(
616 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617
618 // Dispatch to the first bytecode handler for the function.
Ben Murdochc5610432016-08-08 18:44:38 +0100619 __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000620 kInterpreterBytecodeOffsetRegister, times_1, 0));
Ben Murdochc5610432016-08-08 18:44:38 +0100621 __ mov(ebx, Operand(kInterpreterDispatchTableRegister, ebx,
622 times_pointer_size, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623 __ call(ebx);
Ben Murdochc5610432016-08-08 18:44:38 +0100624 masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100625
Ben Murdochc5610432016-08-08 18:44:38 +0100626 // The return value is in eax.
627
628 // Get the arguments + reciever count.
629 __ mov(ebx, Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
630 __ mov(ebx, FieldOperand(ebx, BytecodeArray::kParameterSizeOffset));
631
632 // Leave the frame (also dropping the register file).
633 __ leave();
634
635 // Drop receiver + arguments and return.
636 __ pop(ecx);
637 __ add(esp, ebx);
638 __ push(ecx);
639 __ ret(0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100640
641 // Load debug copy of the bytecode array.
642 __ bind(&load_debug_bytecode_array);
643 Register debug_info = kInterpreterBytecodeArrayRegister;
644 __ mov(debug_info, FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset));
645 __ mov(kInterpreterBytecodeArrayRegister,
646 FieldOperand(debug_info, DebugInfo::kAbstractCodeIndex));
647 __ jmp(&bytecode_array_loaded);
Ben Murdochc5610432016-08-08 18:44:38 +0100648
649 // If the bytecode array is no longer present, then the underlying function
650 // has been switched to a different kind of code and we heal the closure by
651 // switching the code entry field over to the new code object as well.
652 __ bind(&bytecode_array_not_present);
653 __ pop(edx); // Callee's new target.
654 __ pop(edi); // Callee's JS function.
655 __ pop(esi); // Callee's context.
656 __ leave(); // Leave the frame so we can tail call.
657 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
658 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
659 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
660 __ mov(FieldOperand(edi, JSFunction::kCodeEntryOffset), ecx);
661 __ RecordWriteCodeEntryField(edi, ecx, ebx);
662 __ jmp(ecx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663}
664
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000665static void Generate_InterpreterPushArgs(MacroAssembler* masm,
666 Register array_limit) {
667 // ----------- S t a t e -------------
668 // -- ebx : Pointer to the last argument in the args array.
669 // -- array_limit : Pointer to one before the first argument in the
670 // args array.
671 // -----------------------------------
672 Label loop_header, loop_check;
673 __ jmp(&loop_check);
674 __ bind(&loop_header);
675 __ Push(Operand(ebx, 0));
676 __ sub(ebx, Immediate(kPointerSize));
677 __ bind(&loop_check);
678 __ cmp(ebx, array_limit);
679 __ j(greater, &loop_header, Label::kNear);
680}
681
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000682// static
Ben Murdoch097c5b22016-05-18 11:27:45 +0100683void Builtins::Generate_InterpreterPushArgsAndCallImpl(
684 MacroAssembler* masm, TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000685 // ----------- S t a t e -------------
686 // -- eax : the number of arguments (not including the receiver)
687 // -- ebx : the address of the first argument to be pushed. Subsequent
688 // arguments should be consecutive above this, in the same order as
689 // they are to be pushed onto the stack.
690 // -- edi : the target to call (can be any Object).
691 // -----------------------------------
692
693 // Pop return address to allow tail-call after pushing arguments.
694 __ Pop(edx);
695
696 // Find the address of the last argument.
697 __ mov(ecx, eax);
698 __ add(ecx, Immediate(1)); // Add one for receiver.
699 __ shl(ecx, kPointerSizeLog2);
700 __ neg(ecx);
701 __ add(ecx, ebx);
702
703 Generate_InterpreterPushArgs(masm, ecx);
704
705 // Call the target.
706 __ Push(edx); // Re-push return address.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100707 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
708 tail_call_mode),
709 RelocInfo::CODE_TARGET);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000710}
711
712
713// static
714void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
715 // ----------- S t a t e -------------
716 // -- eax : the number of arguments (not including the receiver)
717 // -- edx : the new target
718 // -- edi : the constructor
719 // -- ebx : the address of the first argument to be pushed. Subsequent
720 // arguments should be consecutive above this, in the same order as
721 // they are to be pushed onto the stack.
722 // -----------------------------------
723
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 // Pop return address to allow tail-call after pushing arguments.
725 __ Pop(ecx);
726
Ben Murdochda12d292016-06-02 14:46:10 +0100727 // Push edi in the slot meant for receiver. We need an extra register
728 // so store edi temporarily on stack.
729 __ Push(edi);
730
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 // Find the address of the last argument.
Ben Murdochda12d292016-06-02 14:46:10 +0100732 __ mov(edi, eax);
733 __ neg(edi);
734 __ shl(edi, kPointerSizeLog2);
735 __ add(edi, ebx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000736
Ben Murdochda12d292016-06-02 14:46:10 +0100737 Generate_InterpreterPushArgs(masm, edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000738
Ben Murdochda12d292016-06-02 14:46:10 +0100739 // Restore the constructor from slot on stack. It was pushed at the slot
740 // meant for receiver.
741 __ mov(edi, Operand(esp, eax, times_pointer_size, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000742
743 // Re-push return address.
744 __ Push(ecx);
745
746 // Call the constructor with unmodified eax, edi, ebi values.
747 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
748}
749
Ben Murdochc5610432016-08-08 18:44:38 +0100750void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
751 // Set the return address to the correct point in the interpreter entry
752 // trampoline.
753 Smi* interpreter_entry_return_pc_offset(
754 masm->isolate()->heap()->interpreter_entry_return_pc_offset());
755 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0));
756 __ LoadHeapObject(ebx,
757 masm->isolate()->builtins()->InterpreterEntryTrampoline());
758 __ add(ebx, Immediate(interpreter_entry_return_pc_offset->value() +
759 Code::kHeaderSize - kHeapObjectTag));
760 __ push(ebx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761
Ben Murdochc5610432016-08-08 18:44:38 +0100762 // Initialize the dispatch table register.
763 __ mov(kInterpreterDispatchTableRegister,
764 Immediate(ExternalReference::interpreter_dispatch_table_address(
765 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000766
767 // Get the bytecode array pointer from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000768 __ mov(kInterpreterBytecodeArrayRegister,
Ben Murdochc5610432016-08-08 18:44:38 +0100769 Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770
771 if (FLAG_debug_code) {
772 // Check function data field is actually a BytecodeArray object.
773 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
774 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
775 ebx);
776 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
777 }
778
779 // Get the target bytecode offset from the frame.
Ben Murdochc5610432016-08-08 18:44:38 +0100780 __ mov(kInterpreterBytecodeOffsetRegister,
781 Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000782 __ SmiUntag(kInterpreterBytecodeOffsetRegister);
783
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000784 // Dispatch to the target bytecode.
Ben Murdochc5610432016-08-08 18:44:38 +0100785 __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000786 kInterpreterBytecodeOffsetRegister, times_1, 0));
Ben Murdochc5610432016-08-08 18:44:38 +0100787 __ mov(ebx, Operand(kInterpreterDispatchTableRegister, ebx,
788 times_pointer_size, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000789 __ jmp(ebx);
790}
791
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000792void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
Ben Murdochc5610432016-08-08 18:44:38 +0100793 // ----------- S t a t e -------------
794 // -- eax : argument count (preserved for callee)
795 // -- edx : new target (preserved for callee)
796 // -- edi : target function (preserved for callee)
797 // -----------------------------------
798 // First lookup code, maybe we don't need to compile!
799 Label gotta_call_runtime, gotta_call_runtime_no_stack;
800 Label maybe_call_runtime;
801 Label try_shared;
802 Label loop_top, loop_bottom;
803
804 Register closure = edi;
805 Register new_target = edx;
806 Register argument_count = eax;
807
808 __ push(argument_count);
809 __ push(new_target);
810 __ push(closure);
811
812 Register map = argument_count;
813 Register index = ebx;
814 __ mov(map, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset));
815 __ mov(map, FieldOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
816 __ mov(index, FieldOperand(map, FixedArray::kLengthOffset));
817 __ cmp(index, Immediate(Smi::FromInt(2)));
818 __ j(less, &gotta_call_runtime);
819
820 // Find literals.
821 // edx : native context
822 // ebx : length / index
823 // eax : optimized code map
824 // stack[0] : new target
825 // stack[4] : closure
826 Register native_context = edx;
827 __ mov(native_context, NativeContextOperand());
828
829 __ bind(&loop_top);
830 Register temp = edi;
831
832 // Does the native context match?
833 __ mov(temp, FieldOperand(map, index, times_half_pointer_size,
834 SharedFunctionInfo::kOffsetToPreviousContext));
835 __ mov(temp, FieldOperand(temp, WeakCell::kValueOffset));
836 __ cmp(temp, native_context);
837 __ j(not_equal, &loop_bottom);
838 // OSR id set to none?
839 __ mov(temp, FieldOperand(map, index, times_half_pointer_size,
840 SharedFunctionInfo::kOffsetToPreviousOsrAstId));
841 const int bailout_id = BailoutId::None().ToInt();
842 __ cmp(temp, Immediate(Smi::FromInt(bailout_id)));
843 __ j(not_equal, &loop_bottom);
844 // Literals available?
845 __ mov(temp, FieldOperand(map, index, times_half_pointer_size,
846 SharedFunctionInfo::kOffsetToPreviousLiterals));
847 __ mov(temp, FieldOperand(temp, WeakCell::kValueOffset));
848 __ JumpIfSmi(temp, &gotta_call_runtime);
849
850 // Save the literals in the closure.
851 __ mov(ecx, Operand(esp, 0));
852 __ mov(FieldOperand(ecx, JSFunction::kLiteralsOffset), temp);
853 __ push(index);
854 __ RecordWriteField(ecx, JSFunction::kLiteralsOffset, temp, index,
855 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
856 __ pop(index);
857
858 // Code available?
859 Register entry = ecx;
860 __ mov(entry, FieldOperand(map, index, times_half_pointer_size,
861 SharedFunctionInfo::kOffsetToPreviousCachedCode));
862 __ mov(entry, FieldOperand(entry, WeakCell::kValueOffset));
863 __ JumpIfSmi(entry, &maybe_call_runtime);
864
865 // Found literals and code. Get them into the closure and return.
866 __ pop(closure);
867 // Store code entry in the closure.
868 __ lea(entry, FieldOperand(entry, Code::kHeaderSize));
869
870 Label install_optimized_code_and_tailcall;
871 __ bind(&install_optimized_code_and_tailcall);
872 __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry);
873 __ RecordWriteCodeEntryField(closure, entry, eax);
874
875 // Link the closure into the optimized function list.
876 // ecx : code entry
877 // edx : native context
878 // edi : closure
879 __ mov(ebx,
880 ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST));
881 __ mov(FieldOperand(closure, JSFunction::kNextFunctionLinkOffset), ebx);
882 __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, ebx, eax,
883 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
884 const int function_list_offset =
885 Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST);
886 __ mov(ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST),
887 closure);
888 // Save closure before the write barrier.
889 __ mov(ebx, closure);
890 __ RecordWriteContextSlot(native_context, function_list_offset, closure, eax,
891 kDontSaveFPRegs);
892 __ mov(closure, ebx);
893 __ pop(new_target);
894 __ pop(argument_count);
895 __ jmp(entry);
896
897 __ bind(&loop_bottom);
898 __ sub(index, Immediate(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
899 __ cmp(index, Immediate(Smi::FromInt(1)));
900 __ j(greater, &loop_top);
901
902 // We found neither literals nor code.
903 __ jmp(&gotta_call_runtime);
904
905 __ bind(&maybe_call_runtime);
906 __ pop(closure);
907
908 // Last possibility. Check the context free optimized code map entry.
909 __ mov(entry, FieldOperand(map, FixedArray::kHeaderSize +
910 SharedFunctionInfo::kSharedCodeIndex));
911 __ mov(entry, FieldOperand(entry, WeakCell::kValueOffset));
912 __ JumpIfSmi(entry, &try_shared);
913
914 // Store code entry in the closure.
915 __ lea(entry, FieldOperand(entry, Code::kHeaderSize));
916 __ jmp(&install_optimized_code_and_tailcall);
917
918 __ bind(&try_shared);
919 __ pop(new_target);
920 __ pop(argument_count);
921 // Is the full code valid?
922 __ mov(entry, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset));
923 __ mov(entry, FieldOperand(entry, SharedFunctionInfo::kCodeOffset));
924 __ mov(ebx, FieldOperand(entry, Code::kFlagsOffset));
925 __ and_(ebx, Code::KindField::kMask);
926 __ shr(ebx, Code::KindField::kShift);
927 __ cmp(ebx, Immediate(Code::BUILTIN));
928 __ j(equal, &gotta_call_runtime_no_stack);
929 // Yes, install the full code.
930 __ lea(entry, FieldOperand(entry, Code::kHeaderSize));
931 __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry);
932 __ RecordWriteCodeEntryField(closure, entry, ebx);
933 __ jmp(entry);
934
935 __ bind(&gotta_call_runtime);
936 __ pop(closure);
937 __ pop(new_target);
938 __ pop(argument_count);
939 __ bind(&gotta_call_runtime_no_stack);
940
Ben Murdoch097c5b22016-05-18 11:27:45 +0100941 GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000942}
943
Ben Murdochc5610432016-08-08 18:44:38 +0100944void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
945 GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
946}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000947
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000948void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100949 GenerateTailCallToReturnedCode(masm,
950 Runtime::kCompileOptimized_NotConcurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000951}
952
953
954void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100955 GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000956}
957
958
959static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
960 // For now, we are relying on the fact that make_code_young doesn't do any
961 // garbage collection which allows us to save/restore the registers without
962 // worrying about which of them contain pointers. We also don't build an
963 // internal frame to make the code faster, since we shouldn't have to do stack
964 // crawls in MakeCodeYoung. This seems a bit fragile.
965
966 // Re-execute the code that was patched back to the young age when
967 // the stub returns.
968 __ sub(Operand(esp, 0), Immediate(5));
969 __ pushad();
970 __ mov(eax, Operand(esp, 8 * kPointerSize));
971 {
972 FrameScope scope(masm, StackFrame::MANUAL);
973 __ PrepareCallCFunction(2, ebx);
974 __ mov(Operand(esp, 1 * kPointerSize),
975 Immediate(ExternalReference::isolate_address(masm->isolate())));
976 __ mov(Operand(esp, 0), eax);
977 __ CallCFunction(
978 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
979 }
980 __ popad();
981 __ ret(0);
982}
983
984#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
985void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
986 MacroAssembler* masm) { \
987 GenerateMakeCodeYoungAgainCommon(masm); \
988} \
989void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
990 MacroAssembler* masm) { \
991 GenerateMakeCodeYoungAgainCommon(masm); \
992}
993CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
994#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
995
996
997void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
998 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
999 // that make_code_young doesn't do any garbage collection which allows us to
1000 // save/restore the registers without worrying about which of them contain
1001 // pointers.
1002 __ pushad();
1003 __ mov(eax, Operand(esp, 8 * kPointerSize));
1004 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
1005 { // NOLINT
1006 FrameScope scope(masm, StackFrame::MANUAL);
1007 __ PrepareCallCFunction(2, ebx);
1008 __ mov(Operand(esp, 1 * kPointerSize),
1009 Immediate(ExternalReference::isolate_address(masm->isolate())));
1010 __ mov(Operand(esp, 0), eax);
1011 __ CallCFunction(
1012 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
1013 2);
1014 }
1015 __ popad();
1016
1017 // Perform prologue operations usually performed by the young code stub.
1018 __ pop(eax); // Pop return address into scratch register.
1019 __ push(ebp); // Caller's frame pointer.
1020 __ mov(ebp, esp);
1021 __ push(esi); // Callee's context.
1022 __ push(edi); // Callee's JS Function.
1023 __ push(eax); // Push return address after frame prologue.
1024
1025 // Jump to point after the code-age stub.
1026 __ ret(0);
1027}
1028
1029
1030void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
1031 GenerateMakeCodeYoungAgainCommon(masm);
1032}
1033
1034
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001035void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
1036 Generate_MarkCodeAsExecutedOnce(masm);
1037}
1038
1039
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001040static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
1041 SaveFPRegsMode save_doubles) {
1042 // Enter an internal frame.
1043 {
1044 FrameScope scope(masm, StackFrame::INTERNAL);
1045
1046 // Preserve registers across notification, this is important for compiled
1047 // stubs that tail call the runtime on deopts passing their parameters in
1048 // registers.
1049 __ pushad();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001050 __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001051 __ popad();
1052 // Tear down internal frame.
1053 }
1054
1055 __ pop(MemOperand(esp, 0)); // Ignore state offset
1056 __ ret(0); // Return to IC Miss stub, continuation still on stack.
1057}
1058
1059
1060void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
1061 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
1062}
1063
1064
1065void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
1066 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
1067}
1068
1069
1070static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
1071 Deoptimizer::BailoutType type) {
1072 {
1073 FrameScope scope(masm, StackFrame::INTERNAL);
1074
1075 // Pass deoptimization type to the runtime system.
1076 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001077 __ CallRuntime(Runtime::kNotifyDeoptimized);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001078
1079 // Tear down internal frame.
1080 }
1081
1082 // Get the full codegen state from the stack and untag it.
1083 __ mov(ecx, Operand(esp, 1 * kPointerSize));
1084 __ SmiUntag(ecx);
1085
1086 // Switch on the state.
1087 Label not_no_registers, not_tos_eax;
Ben Murdochc5610432016-08-08 18:44:38 +01001088 __ cmp(ecx, static_cast<int>(Deoptimizer::BailoutState::NO_REGISTERS));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001089 __ j(not_equal, &not_no_registers, Label::kNear);
1090 __ ret(1 * kPointerSize); // Remove state.
1091
1092 __ bind(&not_no_registers);
Ben Murdochc5610432016-08-08 18:44:38 +01001093 DCHECK_EQ(kInterpreterAccumulatorRegister.code(), eax.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001094 __ mov(eax, Operand(esp, 2 * kPointerSize));
Ben Murdochc5610432016-08-08 18:44:38 +01001095 __ cmp(ecx, static_cast<int>(Deoptimizer::BailoutState::TOS_REGISTER));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001096 __ j(not_equal, &not_tos_eax, Label::kNear);
1097 __ ret(2 * kPointerSize); // Remove state, eax.
1098
1099 __ bind(&not_tos_eax);
1100 __ Abort(kNoCasesLeft);
1101}
1102
1103
1104void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
1105 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
1106}
1107
1108
1109void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
1110 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
1111}
1112
1113
1114void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
1115 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
1116}
1117
1118
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001119// static
1120void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
1121 int field_index) {
1122 // ----------- S t a t e -------------
1123 // -- esp[0] : return address
1124 // -- esp[4] : receiver
1125 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001126
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001127 // 1. Load receiver into eax and check that it's actually a JSDate object.
1128 Label receiver_not_date;
1129 {
1130 __ mov(eax, Operand(esp, kPointerSize));
1131 __ JumpIfSmi(eax, &receiver_not_date);
1132 __ CmpObjectType(eax, JS_DATE_TYPE, ebx);
1133 __ j(not_equal, &receiver_not_date);
1134 }
1135
1136 // 2. Load the specified date field, falling back to the runtime as necessary.
1137 if (field_index == JSDate::kDateValue) {
1138 __ mov(eax, FieldOperand(eax, JSDate::kValueOffset));
1139 } else {
1140 if (field_index < JSDate::kFirstUncachedField) {
1141 Label stamp_mismatch;
1142 __ mov(edx, Operand::StaticVariable(
1143 ExternalReference::date_cache_stamp(masm->isolate())));
1144 __ cmp(edx, FieldOperand(eax, JSDate::kCacheStampOffset));
1145 __ j(not_equal, &stamp_mismatch, Label::kNear);
1146 __ mov(eax, FieldOperand(
1147 eax, JSDate::kValueOffset + field_index * kPointerSize));
1148 __ ret(1 * kPointerSize);
1149 __ bind(&stamp_mismatch);
1150 }
1151 FrameScope scope(masm, StackFrame::INTERNAL);
1152 __ PrepareCallCFunction(2, ebx);
1153 __ mov(Operand(esp, 0), eax);
1154 __ mov(Operand(esp, 1 * kPointerSize),
1155 Immediate(Smi::FromInt(field_index)));
1156 __ CallCFunction(
1157 ExternalReference::get_date_field_function(masm->isolate()), 2);
1158 }
1159 __ ret(1 * kPointerSize);
1160
1161 // 3. Raise a TypeError if the receiver is not a date.
1162 __ bind(&receiver_not_date);
1163 {
1164 FrameScope scope(masm, StackFrame::MANUAL);
1165 __ EnterFrame(StackFrame::INTERNAL);
1166 __ CallRuntime(Runtime::kThrowNotDateError);
1167 }
1168}
1169
Ben Murdochda12d292016-06-02 14:46:10 +01001170// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001171void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
1172 // ----------- S t a t e -------------
1173 // -- eax : argc
1174 // -- esp[0] : return address
1175 // -- esp[4] : argArray
1176 // -- esp[8] : thisArg
1177 // -- esp[12] : receiver
1178 // -----------------------------------
1179
1180 // 1. Load receiver into edi, argArray into eax (if present), remove all
1181 // arguments from the stack (including the receiver), and push thisArg (if
1182 // present) instead.
1183 {
1184 Label no_arg_array, no_this_arg;
1185 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1186 __ mov(ebx, edx);
1187 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001188 __ test(eax, eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001189 __ j(zero, &no_this_arg, Label::kNear);
1190 {
1191 __ mov(edx, Operand(esp, eax, times_pointer_size, 0));
1192 __ cmp(eax, Immediate(1));
1193 __ j(equal, &no_arg_array, Label::kNear);
1194 __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize));
1195 __ bind(&no_arg_array);
1196 }
1197 __ bind(&no_this_arg);
1198 __ PopReturnAddressTo(ecx);
1199 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1200 __ Push(edx);
1201 __ PushReturnAddressFrom(ecx);
1202 __ Move(eax, ebx);
1203 }
1204
1205 // ----------- S t a t e -------------
1206 // -- eax : argArray
1207 // -- edi : receiver
1208 // -- esp[0] : return address
1209 // -- esp[4] : thisArg
1210 // -----------------------------------
1211
1212 // 2. Make sure the receiver is actually callable.
1213 Label receiver_not_callable;
1214 __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear);
1215 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001216 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1217 Immediate(1 << Map::kIsCallable));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001218 __ j(zero, &receiver_not_callable, Label::kNear);
1219
1220 // 3. Tail call with no arguments if argArray is null or undefined.
1221 Label no_arguments;
1222 __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
1223 __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments,
1224 Label::kNear);
1225
1226 // 4a. Apply the receiver to the given argArray (passing undefined for
1227 // new.target).
1228 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1229 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1230
1231 // 4b. The argArray is either null or undefined, so we tail call without any
1232 // arguments to the receiver.
1233 __ bind(&no_arguments);
1234 {
1235 __ Set(eax, 0);
1236 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1237 }
1238
1239 // 4c. The receiver is not callable, throw an appropriate TypeError.
1240 __ bind(&receiver_not_callable);
1241 {
1242 __ mov(Operand(esp, kPointerSize), edi);
1243 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1244 }
1245}
1246
1247
1248// static
1249void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1250 // Stack Layout:
1251 // esp[0] : Return address
1252 // esp[8] : Argument n
1253 // esp[16] : Argument n-1
1254 // ...
1255 // esp[8 * n] : Argument 1
1256 // esp[8 * (n + 1)] : Receiver (callable to call)
1257 //
1258 // eax contains the number of arguments, n, not counting the receiver.
1259 //
1260 // 1. Make sure we have at least one argument.
1261 {
1262 Label done;
1263 __ test(eax, eax);
1264 __ j(not_zero, &done, Label::kNear);
1265 __ PopReturnAddressTo(ebx);
1266 __ PushRoot(Heap::kUndefinedValueRootIndex);
1267 __ PushReturnAddressFrom(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001268 __ inc(eax);
1269 __ bind(&done);
1270 }
1271
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001272 // 2. Get the callable to call (passed as receiver) from the stack.
1273 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001274
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001275 // 3. Shift arguments and return address one slot down on the stack
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001276 // (overwriting the original receiver). Adjust argument count to make
1277 // the original first argument the new receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001278 {
1279 Label loop;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001280 __ mov(ecx, eax);
1281 __ bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001282 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1283 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001284 __ dec(ecx);
1285 __ j(not_sign, &loop); // While non-negative (to copy return address).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001286 __ pop(ebx); // Discard copy of return address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001287 __ dec(eax); // One fewer argument (first argument is new receiver).
1288 }
1289
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001290 // 4. Call the callable.
1291 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001292}
1293
1294
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001295void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1296 // ----------- S t a t e -------------
1297 // -- eax : argc
1298 // -- esp[0] : return address
1299 // -- esp[4] : argumentsList
1300 // -- esp[8] : thisArgument
1301 // -- esp[12] : target
1302 // -- esp[16] : receiver
1303 // -----------------------------------
1304
1305 // 1. Load target into edi (if present), argumentsList into eax (if present),
1306 // remove all arguments from the stack (including the receiver), and push
1307 // thisArgument (if present) instead.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001308 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001309 Label done;
1310 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1311 __ mov(edx, edi);
1312 __ mov(ebx, edi);
1313 __ cmp(eax, Immediate(1));
1314 __ j(below, &done, Label::kNear);
1315 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1316 __ j(equal, &done, Label::kNear);
1317 __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1318 __ cmp(eax, Immediate(3));
1319 __ j(below, &done, Label::kNear);
1320 __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1321 __ bind(&done);
1322 __ PopReturnAddressTo(ecx);
1323 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1324 __ Push(edx);
1325 __ PushReturnAddressFrom(ecx);
1326 __ Move(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001327 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001328
1329 // ----------- S t a t e -------------
1330 // -- eax : argumentsList
1331 // -- edi : target
1332 // -- esp[0] : return address
1333 // -- esp[4] : thisArgument
1334 // -----------------------------------
1335
1336 // 2. Make sure the target is actually callable.
1337 Label target_not_callable;
1338 __ JumpIfSmi(edi, &target_not_callable, Label::kNear);
1339 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001340 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1341 Immediate(1 << Map::kIsCallable));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001342 __ j(zero, &target_not_callable, Label::kNear);
1343
1344 // 3a. Apply the target to the given argumentsList (passing undefined for
1345 // new.target).
1346 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1347 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1348
1349 // 3b. The target is not callable, throw an appropriate TypeError.
1350 __ bind(&target_not_callable);
1351 {
1352 __ mov(Operand(esp, kPointerSize), edi);
1353 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1354 }
1355}
1356
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001357void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1358 // ----------- S t a t e -------------
1359 // -- eax : argc
1360 // -- esp[0] : return address
1361 // -- esp[4] : new.target (optional)
1362 // -- esp[8] : argumentsList
1363 // -- esp[12] : target
1364 // -- esp[16] : receiver
1365 // -----------------------------------
1366
1367 // 1. Load target into edi (if present), argumentsList into eax (if present),
1368 // new.target into edx (if present, otherwise use target), remove all
1369 // arguments from the stack (including the receiver), and push thisArgument
1370 // (if present) instead.
1371 {
1372 Label done;
1373 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1374 __ mov(edx, edi);
1375 __ mov(ebx, edi);
1376 __ cmp(eax, Immediate(1));
1377 __ j(below, &done, Label::kNear);
1378 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1379 __ mov(edx, edi);
1380 __ j(equal, &done, Label::kNear);
1381 __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1382 __ cmp(eax, Immediate(3));
1383 __ j(below, &done, Label::kNear);
1384 __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1385 __ bind(&done);
1386 __ PopReturnAddressTo(ecx);
1387 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1388 __ PushRoot(Heap::kUndefinedValueRootIndex);
1389 __ PushReturnAddressFrom(ecx);
1390 __ Move(eax, ebx);
1391 }
1392
1393 // ----------- S t a t e -------------
1394 // -- eax : argumentsList
1395 // -- edx : new.target
1396 // -- edi : target
1397 // -- esp[0] : return address
1398 // -- esp[4] : receiver (undefined)
1399 // -----------------------------------
1400
1401 // 2. Make sure the target is actually a constructor.
1402 Label target_not_constructor;
1403 __ JumpIfSmi(edi, &target_not_constructor, Label::kNear);
1404 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001405 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1406 Immediate(1 << Map::kIsConstructor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001407 __ j(zero, &target_not_constructor, Label::kNear);
1408
1409 // 3. Make sure the target is actually a constructor.
1410 Label new_target_not_constructor;
1411 __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear);
1412 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01001413 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1414 Immediate(1 << Map::kIsConstructor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001415 __ j(zero, &new_target_not_constructor, Label::kNear);
1416
1417 // 4a. Construct the target with the given new.target and argumentsList.
1418 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1419
1420 // 4b. The target is not a constructor, throw an appropriate TypeError.
1421 __ bind(&target_not_constructor);
1422 {
1423 __ mov(Operand(esp, kPointerSize), edi);
1424 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1425 }
1426
1427 // 4c. The new.target is not a constructor, throw an appropriate TypeError.
1428 __ bind(&new_target_not_constructor);
1429 {
1430 __ mov(Operand(esp, kPointerSize), edx);
1431 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1432 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001433}
1434
1435
1436void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1437 // ----------- S t a t e -------------
1438 // -- eax : argc
1439 // -- esp[0] : return address
1440 // -- esp[4] : last argument
1441 // -----------------------------------
1442 Label generic_array_code;
1443
1444 // Get the InternalArray function.
1445 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1446
1447 if (FLAG_debug_code) {
1448 // Initial map for the builtin InternalArray function should be a map.
1449 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1450 // Will both indicate a NULL and a Smi.
1451 __ test(ebx, Immediate(kSmiTagMask));
1452 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1453 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1454 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1455 }
1456
1457 // Run the native code for the InternalArray function called as a normal
1458 // function.
1459 // tail call a stub
1460 InternalArrayConstructorStub stub(masm->isolate());
1461 __ TailCallStub(&stub);
1462}
1463
1464
1465void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1466 // ----------- S t a t e -------------
1467 // -- eax : argc
1468 // -- esp[0] : return address
1469 // -- esp[4] : last argument
1470 // -----------------------------------
1471 Label generic_array_code;
1472
1473 // Get the Array function.
1474 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001475 __ mov(edx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476
1477 if (FLAG_debug_code) {
1478 // Initial map for the builtin Array function should be a map.
1479 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1480 // Will both indicate a NULL and a Smi.
1481 __ test(ebx, Immediate(kSmiTagMask));
1482 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1483 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1484 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1485 }
1486
1487 // Run the native code for the Array function called as a normal function.
1488 // tail call a stub
1489 __ mov(ebx, masm->isolate()->factory()->undefined_value());
1490 ArrayConstructorStub stub(masm->isolate());
1491 __ TailCallStub(&stub);
1492}
1493
1494
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001495// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01001496void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
1497 // ----------- S t a t e -------------
1498 // -- eax : number of arguments
1499 // -- esp[0] : return address
1500 // -- esp[(argc - n) * 8] : arg[n] (zero-based)
1501 // -- esp[(argc + 1) * 8] : receiver
1502 // -----------------------------------
1503 Condition const cc = (kind == MathMaxMinKind::kMin) ? below : above;
1504 Heap::RootListIndex const root_index =
1505 (kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
1506 : Heap::kMinusInfinityValueRootIndex;
1507 const int reg_sel = (kind == MathMaxMinKind::kMin) ? 1 : 0;
1508
1509 // Load the accumulator with the default return value (either -Infinity or
1510 // +Infinity), with the tagged value in edx and the double value in stx_0.
1511 __ LoadRoot(edx, root_index);
1512 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1513 __ Move(ecx, eax);
1514
1515 Label done_loop, loop;
1516 __ bind(&loop);
1517 {
1518 // Check if all parameters done.
1519 __ test(ecx, ecx);
1520 __ j(zero, &done_loop);
1521
1522 // Load the next parameter tagged value into ebx.
1523 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1524
1525 // Load the double value of the parameter into stx_1, maybe converting the
1526 // parameter to a number first using the ToNumberStub if necessary.
1527 Label convert, convert_smi, convert_number, done_convert;
1528 __ bind(&convert);
1529 __ JumpIfSmi(ebx, &convert_smi);
1530 __ JumpIfRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1531 Heap::kHeapNumberMapRootIndex, &convert_number);
1532 {
1533 // Parameter is not a Number, use the ToNumberStub to convert it.
1534 FrameScope scope(masm, StackFrame::INTERNAL);
1535 __ SmiTag(eax);
1536 __ SmiTag(ecx);
1537 __ Push(eax);
1538 __ Push(ecx);
1539 __ Push(edx);
1540 __ mov(eax, ebx);
1541 ToNumberStub stub(masm->isolate());
1542 __ CallStub(&stub);
1543 __ mov(ebx, eax);
1544 __ Pop(edx);
1545 __ Pop(ecx);
1546 __ Pop(eax);
1547 {
1548 // Restore the double accumulator value (stX_0).
1549 Label restore_smi, done_restore;
1550 __ JumpIfSmi(edx, &restore_smi, Label::kNear);
1551 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1552 __ jmp(&done_restore, Label::kNear);
1553 __ bind(&restore_smi);
1554 __ SmiUntag(edx);
1555 __ push(edx);
1556 __ fild_s(Operand(esp, 0));
1557 __ pop(edx);
1558 __ SmiTag(edx);
1559 __ bind(&done_restore);
1560 }
1561 __ SmiUntag(ecx);
1562 __ SmiUntag(eax);
1563 }
1564 __ jmp(&convert);
1565 __ bind(&convert_number);
1566 // Load another value into stx_1
1567 __ fld_d(FieldOperand(ebx, HeapNumber::kValueOffset));
1568 __ fxch();
1569 __ jmp(&done_convert, Label::kNear);
1570 __ bind(&convert_smi);
1571 __ SmiUntag(ebx);
1572 __ push(ebx);
1573 __ fild_s(Operand(esp, 0));
1574 __ pop(ebx);
1575 __ fxch();
1576 __ SmiTag(ebx);
1577 __ bind(&done_convert);
1578
1579 // Perform the actual comparison with the accumulator value on the left hand
1580 // side (stx_0) and the next parameter value on the right hand side (stx_1).
1581 Label compare_equal, compare_nan, compare_swap, done_compare;
1582
1583 // Duplicates the 2 float data for FCmp
1584 __ fld(1);
1585 __ fld(1);
1586 __ FCmp();
1587 __ j(parity_even, &compare_nan, Label::kNear);
1588 __ j(cc, &done_compare, Label::kNear);
1589 __ j(equal, &compare_equal, Label::kNear);
1590
1591 // Result is on the right hand side(stx_0).
1592 __ bind(&compare_swap);
1593 __ fxch();
1594 __ mov(edx, ebx);
1595 __ jmp(&done_compare, Label::kNear);
1596
1597 // At least one side is NaN, which means that the result will be NaN too.
1598 __ bind(&compare_nan);
1599 // Set the result on the right hand side (stx_0) to nan
1600 __ fstp(0);
1601 __ LoadRoot(edx, Heap::kNanValueRootIndex);
1602 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
1603 __ jmp(&done_compare, Label::kNear);
1604
1605 // Left and right hand side are equal, check for -0 vs. +0.
1606 __ bind(&compare_equal);
1607 // Check the sign of the value in reg_sel
1608 __ fld(reg_sel);
1609 __ FXamSign();
1610 __ j(not_zero, &compare_swap);
1611
1612 __ bind(&done_compare);
1613 // The right result is on the right hand side(stx_0)
1614 // and can remove the useless stx_1 now.
1615 __ fxch();
1616 __ fstp(0);
1617 __ dec(ecx);
1618 __ jmp(&loop);
1619 }
1620
1621 __ bind(&done_loop);
1622 __ PopReturnAddressTo(ecx);
1623 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1624 __ PushReturnAddressFrom(ecx);
1625 __ mov(eax, edx);
1626 __ Ret();
1627}
1628
1629// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001630void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001631 // ----------- S t a t e -------------
1632 // -- eax : number of arguments
1633 // -- edi : constructor function
1634 // -- esp[0] : return address
1635 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1636 // -- esp[(argc + 1) * 4] : receiver
1637 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001638
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001639 // 1. Load the first argument into eax and get rid of the rest (including the
1640 // receiver).
1641 Label no_arguments;
1642 {
1643 __ test(eax, eax);
1644 __ j(zero, &no_arguments, Label::kNear);
1645 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1646 __ PopReturnAddressTo(ecx);
1647 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1648 __ PushReturnAddressFrom(ecx);
1649 __ mov(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001650 }
1651
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001652 // 2a. Convert the first argument to a number.
1653 ToNumberStub stub(masm->isolate());
1654 __ TailCallStub(&stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001655
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001656 // 2b. No arguments, return +0 (already in eax).
1657 __ bind(&no_arguments);
1658 __ ret(1 * kPointerSize);
1659}
1660
1661
1662// static
1663void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664 // ----------- S t a t e -------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001665 // -- eax : number of arguments
1666 // -- edi : constructor function
1667 // -- edx : new target
1668 // -- esp[0] : return address
1669 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1670 // -- esp[(argc + 1) * 4] : receiver
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001671 // -----------------------------------
1672
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001673 // 1. Make sure we operate in the context of the called function.
1674 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001675
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001676 // 2. Load the first argument into ebx and get rid of the rest (including the
1677 // receiver).
1678 {
1679 Label no_arguments, done;
1680 __ test(eax, eax);
1681 __ j(zero, &no_arguments, Label::kNear);
1682 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1683 __ jmp(&done, Label::kNear);
1684 __ bind(&no_arguments);
1685 __ Move(ebx, Smi::FromInt(0));
1686 __ bind(&done);
1687 __ PopReturnAddressTo(ecx);
1688 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1689 __ PushReturnAddressFrom(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001690 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001691
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001692 // 3. Make sure ebx is a number.
1693 {
1694 Label done_convert;
1695 __ JumpIfSmi(ebx, &done_convert);
1696 __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1697 Heap::kHeapNumberMapRootIndex);
1698 __ j(equal, &done_convert);
1699 {
1700 FrameScope scope(masm, StackFrame::INTERNAL);
1701 __ Push(edi);
1702 __ Push(edx);
1703 __ Move(eax, ebx);
1704 ToNumberStub stub(masm->isolate());
1705 __ CallStub(&stub);
1706 __ Move(ebx, eax);
1707 __ Pop(edx);
1708 __ Pop(edi);
1709 }
1710 __ bind(&done_convert);
1711 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001712
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001713 // 4. Check if new target and constructor differ.
1714 Label new_object;
1715 __ cmp(edx, edi);
1716 __ j(not_equal, &new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001717
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001718 // 5. Allocate a JSValue wrapper for the number.
1719 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1720 __ Ret();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001721
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001722 // 6. Fallback to the runtime to create new object.
1723 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001724 {
1725 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001726 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001727 FastNewObjectStub stub(masm->isolate());
1728 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001729 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001730 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001731 __ Ret();
1732}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001733
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001734
1735// static
1736void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
1737 // ----------- S t a t e -------------
1738 // -- eax : number of arguments
1739 // -- edi : constructor function
1740 // -- esp[0] : return address
1741 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1742 // -- esp[(argc + 1) * 4] : receiver
1743 // -----------------------------------
1744
1745 // 1. Load the first argument into eax and get rid of the rest (including the
1746 // receiver).
1747 Label no_arguments;
1748 {
1749 __ test(eax, eax);
1750 __ j(zero, &no_arguments, Label::kNear);
1751 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1752 __ PopReturnAddressTo(ecx);
1753 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1754 __ PushReturnAddressFrom(ecx);
1755 __ mov(eax, ebx);
1756 }
1757
1758 // 2a. At least one argument, return eax if it's a string, otherwise
1759 // dispatch to appropriate conversion.
1760 Label to_string, symbol_descriptive_string;
1761 {
1762 __ JumpIfSmi(eax, &to_string, Label::kNear);
1763 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
1764 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
1765 __ j(above, &to_string, Label::kNear);
1766 __ j(equal, &symbol_descriptive_string, Label::kNear);
1767 __ Ret();
1768 }
1769
1770 // 2b. No arguments, return the empty string (and pop the receiver).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001771 __ bind(&no_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001772 {
1773 __ LoadRoot(eax, Heap::kempty_stringRootIndex);
1774 __ ret(1 * kPointerSize);
1775 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001776
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001777 // 3a. Convert eax to a string.
1778 __ bind(&to_string);
1779 {
1780 ToStringStub stub(masm->isolate());
1781 __ TailCallStub(&stub);
1782 }
1783
1784 // 3b. Convert symbol in eax to a string.
1785 __ bind(&symbol_descriptive_string);
1786 {
1787 __ PopReturnAddressTo(ecx);
1788 __ Push(eax);
1789 __ PushReturnAddressFrom(ecx);
1790 __ TailCallRuntime(Runtime::kSymbolDescriptiveString);
1791 }
1792}
1793
1794
1795// static
1796void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
1797 // ----------- S t a t e -------------
1798 // -- eax : number of arguments
1799 // -- edi : constructor function
1800 // -- edx : new target
1801 // -- esp[0] : return address
1802 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1803 // -- esp[(argc + 1) * 4] : receiver
1804 // -----------------------------------
1805
1806 // 1. Make sure we operate in the context of the called function.
1807 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1808
1809 // 2. Load the first argument into ebx and get rid of the rest (including the
1810 // receiver).
1811 {
1812 Label no_arguments, done;
1813 __ test(eax, eax);
1814 __ j(zero, &no_arguments, Label::kNear);
1815 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1816 __ jmp(&done, Label::kNear);
1817 __ bind(&no_arguments);
1818 __ LoadRoot(ebx, Heap::kempty_stringRootIndex);
1819 __ bind(&done);
1820 __ PopReturnAddressTo(ecx);
1821 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1822 __ PushReturnAddressFrom(ecx);
1823 }
1824
1825 // 3. Make sure ebx is a string.
1826 {
1827 Label convert, done_convert;
1828 __ JumpIfSmi(ebx, &convert, Label::kNear);
1829 __ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, ecx);
1830 __ j(below, &done_convert);
1831 __ bind(&convert);
1832 {
1833 FrameScope scope(masm, StackFrame::INTERNAL);
1834 ToStringStub stub(masm->isolate());
1835 __ Push(edi);
1836 __ Push(edx);
1837 __ Move(eax, ebx);
1838 __ CallStub(&stub);
1839 __ Move(ebx, eax);
1840 __ Pop(edx);
1841 __ Pop(edi);
1842 }
1843 __ bind(&done_convert);
1844 }
1845
1846 // 4. Check if new target and constructor differ.
1847 Label new_object;
1848 __ cmp(edx, edi);
1849 __ j(not_equal, &new_object);
1850
1851 // 5. Allocate a JSValue wrapper for the string.
1852 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1853 __ Ret();
1854
1855 // 6. Fallback to the runtime to create new object.
1856 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001857 {
1858 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001859 __ Push(ebx); // the first argument
Ben Murdoch097c5b22016-05-18 11:27:45 +01001860 FastNewObjectStub stub(masm->isolate());
1861 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001862 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001864 __ Ret();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001865}
1866
1867
1868static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1869 Label* stack_overflow) {
1870 // ----------- S t a t e -------------
1871 // -- eax : actual number of arguments
1872 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001873 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001874 // -----------------------------------
1875 // Check the stack for overflow. We are not trying to catch
1876 // interruptions (e.g. debug break and preemption) here, so the "real stack
1877 // limit" is checked.
1878 ExternalReference real_stack_limit =
1879 ExternalReference::address_of_real_stack_limit(masm->isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001880 __ mov(edi, Operand::StaticVariable(real_stack_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001881 // Make ecx the space we have left. The stack might already be overflowed
1882 // here which will cause ecx to become negative.
1883 __ mov(ecx, esp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001884 __ sub(ecx, edi);
1885 // Make edi the space we need for the array when it is unrolled onto the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001886 // stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001887 __ mov(edi, ebx);
1888 __ shl(edi, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889 // Check if the arguments will overflow the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001890 __ cmp(ecx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001891 __ j(less_equal, stack_overflow); // Signed comparison.
1892}
1893
1894
1895static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1896 __ push(ebp);
1897 __ mov(ebp, esp);
1898
1899 // Store the arguments adaptor context sentinel.
1900 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1901
1902 // Push the function on the stack.
1903 __ push(edi);
1904
1905 // Preserve the number of arguments on the stack. Must preserve eax,
1906 // ebx and ecx because these registers are used when copying the
1907 // arguments and the receiver.
1908 STATIC_ASSERT(kSmiTagSize == 1);
1909 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1910 __ push(edi);
1911}
1912
1913
1914static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1915 // Retrieve the number of arguments from the stack.
1916 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1917
1918 // Leave the frame.
1919 __ leave();
1920
1921 // Remove caller arguments from the stack.
1922 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1923 __ pop(ecx);
1924 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1925 __ push(ecx);
1926}
1927
1928
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001929// static
1930void Builtins::Generate_Apply(MacroAssembler* masm) {
1931 // ----------- S t a t e -------------
1932 // -- eax : argumentsList
1933 // -- edi : target
1934 // -- edx : new.target (checked to be constructor or undefined)
1935 // -- esp[0] : return address.
1936 // -- esp[4] : thisArgument
1937 // -----------------------------------
1938
1939 // Create the list of arguments from the array-like argumentsList.
1940 {
1941 Label create_arguments, create_array, create_runtime, done_create;
1942 __ JumpIfSmi(eax, &create_runtime);
1943
1944 // Load the map of argumentsList into ecx.
1945 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
1946
1947 // Load native context into ebx.
1948 __ mov(ebx, NativeContextOperand());
1949
1950 // Check if argumentsList is an (unmodified) arguments object.
1951 __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
1952 __ j(equal, &create_arguments);
1953 __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX));
1954 __ j(equal, &create_arguments);
1955
1956 // Check if argumentsList is a fast JSArray.
1957 __ CmpInstanceType(ecx, JS_ARRAY_TYPE);
1958 __ j(equal, &create_array);
1959
1960 // Ask the runtime to create the list (actually a FixedArray).
1961 __ bind(&create_runtime);
1962 {
1963 FrameScope scope(masm, StackFrame::INTERNAL);
1964 __ Push(edi);
1965 __ Push(edx);
1966 __ Push(eax);
1967 __ CallRuntime(Runtime::kCreateListFromArrayLike);
1968 __ Pop(edx);
1969 __ Pop(edi);
1970 __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset));
1971 __ SmiUntag(ebx);
1972 }
1973 __ jmp(&done_create);
1974
1975 // Try to create the list from an arguments object.
1976 __ bind(&create_arguments);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001977 __ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001978 __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset));
1979 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1980 __ j(not_equal, &create_runtime);
1981 __ SmiUntag(ebx);
1982 __ mov(eax, ecx);
1983 __ jmp(&done_create);
1984
1985 // Try to create the list from a JSArray object.
1986 __ bind(&create_array);
1987 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
1988 __ DecodeField<Map::ElementsKindBits>(ecx);
1989 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
1990 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
1991 STATIC_ASSERT(FAST_ELEMENTS == 2);
1992 __ cmp(ecx, Immediate(FAST_ELEMENTS));
1993 __ j(above, &create_runtime);
1994 __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
1995 __ j(equal, &create_runtime);
1996 __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
1997 __ SmiUntag(ebx);
1998 __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
1999
2000 __ bind(&done_create);
2001 }
2002
2003 // Check for stack overflow.
2004 {
2005 // Check the stack for overflow. We are not trying to catch interruptions
2006 // (i.e. debug break and preemption) here, so check the "real stack limit".
2007 Label done;
2008 ExternalReference real_stack_limit =
2009 ExternalReference::address_of_real_stack_limit(masm->isolate());
2010 __ mov(ecx, Operand::StaticVariable(real_stack_limit));
2011 // Make ecx the space we have left. The stack might already be overflowed
2012 // here which will cause ecx to become negative.
2013 __ neg(ecx);
2014 __ add(ecx, esp);
2015 __ sar(ecx, kPointerSizeLog2);
2016 // Check if the arguments will overflow the stack.
2017 __ cmp(ecx, ebx);
2018 __ j(greater, &done, Label::kNear); // Signed comparison.
2019 __ TailCallRuntime(Runtime::kThrowStackOverflow);
2020 __ bind(&done);
2021 }
2022
2023 // ----------- S t a t e -------------
2024 // -- edi : target
2025 // -- eax : args (a FixedArray built from argumentsList)
2026 // -- ebx : len (number of elements to push from args)
2027 // -- edx : new.target (checked to be constructor or undefined)
2028 // -- esp[0] : return address.
2029 // -- esp[4] : thisArgument
2030 // -----------------------------------
2031
2032 // Push arguments onto the stack (thisArgument is already on the stack).
2033 {
2034 __ push(edx);
2035 __ fld_s(MemOperand(esp, 0));
2036 __ lea(esp, Operand(esp, kFloatSize));
2037
2038 __ PopReturnAddressTo(edx);
2039 __ Move(ecx, Immediate(0));
2040 Label done, loop;
2041 __ bind(&loop);
2042 __ cmp(ecx, ebx);
2043 __ j(equal, &done, Label::kNear);
2044 __ Push(
2045 FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
2046 __ inc(ecx);
2047 __ jmp(&loop);
2048 __ bind(&done);
2049 __ PushReturnAddressFrom(edx);
2050
2051 __ lea(esp, Operand(esp, -kFloatSize));
2052 __ fstp_s(MemOperand(esp, 0));
2053 __ pop(edx);
2054
2055 __ Move(eax, ebx);
2056 }
2057
2058 // Dispatch to Call or Construct depending on whether new.target is undefined.
2059 {
2060 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
2061 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
2062 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
2063 }
2064}
2065
Ben Murdoch097c5b22016-05-18 11:27:45 +01002066namespace {
2067
2068// Drops top JavaScript frame and an arguments adaptor frame below it (if
2069// present) preserving all the arguments prepared for current call.
2070// Does nothing if debugger is currently active.
2071// ES6 14.6.3. PrepareForTailCall
2072//
2073// Stack structure for the function g() tail calling f():
2074//
2075// ------- Caller frame: -------
2076// | ...
2077// | g()'s arg M
2078// | ...
2079// | g()'s arg 1
2080// | g()'s receiver arg
2081// | g()'s caller pc
2082// ------- g()'s frame: -------
2083// | g()'s caller fp <- fp
2084// | g()'s context
2085// | function pointer: g
2086// | -------------------------
2087// | ...
2088// | ...
2089// | f()'s arg N
2090// | ...
2091// | f()'s arg 1
2092// | f()'s receiver arg
2093// | f()'s caller pc <- sp
2094// ----------------------
2095//
2096void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
2097 Register scratch1, Register scratch2,
2098 Register scratch3) {
2099 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
2100 Comment cmnt(masm, "[ PrepareForTailCall");
2101
Ben Murdochda12d292016-06-02 14:46:10 +01002102 // Prepare for tail call only if ES2015 tail call elimination is enabled.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002103 Label done;
Ben Murdochda12d292016-06-02 14:46:10 +01002104 ExternalReference is_tail_call_elimination_enabled =
2105 ExternalReference::is_tail_call_elimination_enabled_address(
2106 masm->isolate());
2107 __ movzx_b(scratch1,
2108 Operand::StaticVariable(is_tail_call_elimination_enabled));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002109 __ cmp(scratch1, Immediate(0));
Ben Murdochda12d292016-06-02 14:46:10 +01002110 __ j(equal, &done, Label::kNear);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002111
2112 // Drop possible interpreter handler/stub frame.
2113 {
2114 Label no_interpreter_frame;
Ben Murdochda12d292016-06-02 14:46:10 +01002115 __ cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
Ben Murdoch097c5b22016-05-18 11:27:45 +01002116 Immediate(Smi::FromInt(StackFrame::STUB)));
2117 __ j(not_equal, &no_interpreter_frame, Label::kNear);
2118 __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2119 __ bind(&no_interpreter_frame);
2120 }
2121
2122 // Check if next frame is an arguments adaptor frame.
Ben Murdochda12d292016-06-02 14:46:10 +01002123 Register caller_args_count_reg = scratch1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002124 Label no_arguments_adaptor, formal_parameter_count_loaded;
2125 __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01002126 __ cmp(Operand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset),
Ben Murdoch097c5b22016-05-18 11:27:45 +01002127 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2128 __ j(not_equal, &no_arguments_adaptor, Label::kNear);
2129
Ben Murdochda12d292016-06-02 14:46:10 +01002130 // Drop current frame and load arguments count from arguments adaptor frame.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002131 __ mov(ebp, scratch2);
Ben Murdochda12d292016-06-02 14:46:10 +01002132 __ mov(caller_args_count_reg,
2133 Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
2134 __ SmiUntag(caller_args_count_reg);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002135 __ jmp(&formal_parameter_count_loaded, Label::kNear);
2136
2137 __ bind(&no_arguments_adaptor);
2138 // Load caller's formal parameter count
2139 __ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2140 __ mov(scratch1,
2141 FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
2142 __ mov(
Ben Murdochda12d292016-06-02 14:46:10 +01002143 caller_args_count_reg,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002144 FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01002145 __ SmiUntag(caller_args_count_reg);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002146
2147 __ bind(&formal_parameter_count_loaded);
2148
Ben Murdochda12d292016-06-02 14:46:10 +01002149 ParameterCount callee_args_count(args_reg);
2150 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
2151 scratch3, ReturnAddressState::kOnStack, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002152 __ bind(&done);
2153}
2154} // namespace
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002155
2156// static
2157void Builtins::Generate_CallFunction(MacroAssembler* masm,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002158 ConvertReceiverMode mode,
2159 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002160 // ----------- S t a t e -------------
2161 // -- eax : the number of arguments (not including the receiver)
2162 // -- edi : the function to call (checked to be a JSFunction)
2163 // -----------------------------------
2164 __ AssertFunction(edi);
2165
2166 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
2167 // Check that the function is not a "classConstructor".
2168 Label class_constructor;
2169 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2170 __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
Ben Murdochda12d292016-06-02 14:46:10 +01002171 Immediate(SharedFunctionInfo::kClassConstructorBitsWithinByte));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002172 __ j(not_zero, &class_constructor);
2173
2174 // Enter the context of the function; ToObject has to run in the function
2175 // context, and we also need to take the global proxy from the function
2176 // context in case of conversion.
2177 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
2178 SharedFunctionInfo::kStrictModeByteOffset);
2179 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2180 // We need to convert the receiver for non-native sloppy mode functions.
2181 Label done_convert;
2182 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
Ben Murdochda12d292016-06-02 14:46:10 +01002183 Immediate((1 << SharedFunctionInfo::kNativeBitWithinByte) |
2184 (1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002185 __ j(not_zero, &done_convert);
2186 {
2187 // ----------- S t a t e -------------
2188 // -- eax : the number of arguments (not including the receiver)
2189 // -- edx : the shared function info.
2190 // -- edi : the function to call (checked to be a JSFunction)
2191 // -- esi : the function context.
2192 // -----------------------------------
2193
2194 if (mode == ConvertReceiverMode::kNullOrUndefined) {
2195 // Patch receiver to global proxy.
2196 __ LoadGlobalProxy(ecx);
2197 } else {
2198 Label convert_to_object, convert_receiver;
2199 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
2200 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
2201 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2202 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
2203 __ j(above_equal, &done_convert);
2204 if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
2205 Label convert_global_proxy;
2206 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
2207 &convert_global_proxy, Label::kNear);
2208 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
2209 Label::kNear);
2210 __ bind(&convert_global_proxy);
2211 {
2212 // Patch receiver to global proxy.
2213 __ LoadGlobalProxy(ecx);
2214 }
2215 __ jmp(&convert_receiver);
2216 }
2217 __ bind(&convert_to_object);
2218 {
2219 // Convert receiver using ToObject.
2220 // TODO(bmeurer): Inline the allocation here to avoid building the frame
2221 // in the fast case? (fall back to AllocateInNewSpace?)
2222 FrameScope scope(masm, StackFrame::INTERNAL);
2223 __ SmiTag(eax);
2224 __ Push(eax);
2225 __ Push(edi);
2226 __ mov(eax, ecx);
2227 ToObjectStub stub(masm->isolate());
2228 __ CallStub(&stub);
2229 __ mov(ecx, eax);
2230 __ Pop(edi);
2231 __ Pop(eax);
2232 __ SmiUntag(eax);
2233 }
2234 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2235 __ bind(&convert_receiver);
2236 }
2237 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
2238 }
2239 __ bind(&done_convert);
2240
2241 // ----------- S t a t e -------------
2242 // -- eax : the number of arguments (not including the receiver)
2243 // -- edx : the shared function info.
2244 // -- edi : the function to call (checked to be a JSFunction)
2245 // -- esi : the function context.
2246 // -----------------------------------
2247
Ben Murdoch097c5b22016-05-18 11:27:45 +01002248 if (tail_call_mode == TailCallMode::kAllow) {
2249 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2250 // Reload shared function info.
2251 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2252 }
2253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002254 __ mov(ebx,
2255 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2256 __ SmiUntag(ebx);
2257 ParameterCount actual(eax);
2258 ParameterCount expected(ebx);
2259 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
2260 CheckDebugStepCallWrapper());
2261 // The function is a "classConstructor", need to raise an exception.
2262 __ bind(&class_constructor);
2263 {
2264 FrameScope frame(masm, StackFrame::INTERNAL);
2265 __ push(edi);
2266 __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
2267 }
2268}
2269
2270
2271namespace {
2272
2273void Generate_PushBoundArguments(MacroAssembler* masm) {
2274 // ----------- S t a t e -------------
2275 // -- eax : the number of arguments (not including the receiver)
2276 // -- edx : new.target (only in case of [[Construct]])
2277 // -- edi : target (checked to be a JSBoundFunction)
2278 // -----------------------------------
2279
2280 // Load [[BoundArguments]] into ecx and length of that into ebx.
2281 Label no_bound_arguments;
2282 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2283 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2284 __ SmiUntag(ebx);
2285 __ test(ebx, ebx);
2286 __ j(zero, &no_bound_arguments);
2287 {
2288 // ----------- S t a t e -------------
2289 // -- eax : the number of arguments (not including the receiver)
2290 // -- edx : new.target (only in case of [[Construct]])
2291 // -- edi : target (checked to be a JSBoundFunction)
2292 // -- ecx : the [[BoundArguments]] (implemented as FixedArray)
2293 // -- ebx : the number of [[BoundArguments]]
2294 // -----------------------------------
2295
2296 // Reserve stack space for the [[BoundArguments]].
2297 {
2298 Label done;
2299 __ lea(ecx, Operand(ebx, times_pointer_size, 0));
2300 __ sub(esp, ecx);
2301 // Check the stack for overflow. We are not trying to catch interruptions
2302 // (i.e. debug break and preemption) here, so check the "real stack
2303 // limit".
2304 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
2305 __ j(greater, &done, Label::kNear); // Signed comparison.
2306 // Restore the stack pointer.
2307 __ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
2308 {
2309 FrameScope scope(masm, StackFrame::MANUAL);
2310 __ EnterFrame(StackFrame::INTERNAL);
2311 __ CallRuntime(Runtime::kThrowStackOverflow);
2312 }
2313 __ bind(&done);
2314 }
2315
2316 // Adjust effective number of arguments to include return address.
2317 __ inc(eax);
2318
2319 // Relocate arguments and return address down the stack.
2320 {
2321 Label loop;
2322 __ Set(ecx, 0);
2323 __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
2324 __ bind(&loop);
2325 __ fld_s(Operand(ebx, ecx, times_pointer_size, 0));
2326 __ fstp_s(Operand(esp, ecx, times_pointer_size, 0));
2327 __ inc(ecx);
2328 __ cmp(ecx, eax);
2329 __ j(less, &loop);
2330 }
2331
2332 // Copy [[BoundArguments]] to the stack (below the arguments).
2333 {
2334 Label loop;
2335 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
2336 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
2337 __ SmiUntag(ebx);
2338 __ bind(&loop);
2339 __ dec(ebx);
2340 __ fld_s(
2341 FieldOperand(ecx, ebx, times_pointer_size, FixedArray::kHeaderSize));
2342 __ fstp_s(Operand(esp, eax, times_pointer_size, 0));
2343 __ lea(eax, Operand(eax, 1));
2344 __ j(greater, &loop);
2345 }
2346
2347 // Adjust effective number of arguments (eax contains the number of
2348 // arguments from the call plus return address plus the number of
2349 // [[BoundArguments]]), so we need to subtract one for the return address.
2350 __ dec(eax);
2351 }
2352 __ bind(&no_bound_arguments);
2353}
2354
2355} // namespace
2356
2357
2358// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002359void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2360 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002361 // ----------- S t a t e -------------
2362 // -- eax : the number of arguments (not including the receiver)
2363 // -- edi : the function to call (checked to be a JSBoundFunction)
2364 // -----------------------------------
2365 __ AssertBoundFunction(edi);
2366
Ben Murdoch097c5b22016-05-18 11:27:45 +01002367 if (tail_call_mode == TailCallMode::kAllow) {
2368 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2369 }
2370
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002371 // Patch the receiver to [[BoundThis]].
2372 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2373 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2374
2375 // Push the [[BoundArguments]] onto the stack.
2376 Generate_PushBoundArguments(masm);
2377
2378 // Call the [[BoundTargetFunction]] via the Call builtin.
2379 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2380 __ mov(ecx, Operand::StaticVariable(ExternalReference(
2381 Builtins::kCall_ReceiverIsAny, masm->isolate())));
2382 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2383 __ jmp(ecx);
2384}
2385
2386
2387// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002388void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2389 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002390 // ----------- S t a t e -------------
2391 // -- eax : the number of arguments (not including the receiver)
2392 // -- edi : the target to call (can be any Object).
2393 // -----------------------------------
2394
2395 Label non_callable, non_function, non_smi;
2396 __ JumpIfSmi(edi, &non_callable);
2397 __ bind(&non_smi);
2398 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002399 __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002400 RelocInfo::CODE_TARGET);
2401 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002402 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002403 RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002404
2405 // Check if target has a [[Call]] internal method.
Ben Murdochda12d292016-06-02 14:46:10 +01002406 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
2407 Immediate(1 << Map::kIsCallable));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002408 __ j(zero, &non_callable);
2409
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002410 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2411 __ j(not_equal, &non_function);
2412
Ben Murdoch097c5b22016-05-18 11:27:45 +01002413 // 0. Prepare for tail call if necessary.
2414 if (tail_call_mode == TailCallMode::kAllow) {
2415 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2416 }
2417
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002418 // 1. Runtime fallback for Proxy [[Call]].
2419 __ PopReturnAddressTo(ecx);
2420 __ Push(edi);
2421 __ PushReturnAddressFrom(ecx);
2422 // Increase the arguments size to include the pushed function and the
2423 // existing receiver on the stack.
2424 __ add(eax, Immediate(2));
2425 // Tail-call to the runtime.
2426 __ JumpToExternalReference(
2427 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2428
2429 // 2. Call to something else, which might have a [[Call]] internal method (if
2430 // not we raise an exception).
2431 __ bind(&non_function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002432 // Overwrite the original receiver with the (original) target.
2433 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2434 // Let the "call_as_function_delegate" take care of the rest.
2435 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2436 __ Jump(masm->isolate()->builtins()->CallFunction(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002437 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002438 RelocInfo::CODE_TARGET);
2439
2440 // 3. Call to something that is not callable.
2441 __ bind(&non_callable);
2442 {
2443 FrameScope scope(masm, StackFrame::INTERNAL);
2444 __ Push(edi);
2445 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2446 }
2447}
2448
2449
2450// static
2451void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2452 // ----------- S t a t e -------------
2453 // -- eax : the number of arguments (not including the receiver)
2454 // -- edx : the new target (checked to be a constructor)
2455 // -- edi : the constructor to call (checked to be a JSFunction)
2456 // -----------------------------------
2457 __ AssertFunction(edi);
2458
2459 // Calling convention for function specific ConstructStubs require
2460 // ebx to contain either an AllocationSite or undefined.
2461 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
2462
2463 // Tail call to the function-specific construct stub (still in the caller
2464 // context at this point).
2465 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2466 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
2467 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2468 __ jmp(ecx);
2469}
2470
2471
2472// static
2473void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2474 // ----------- S t a t e -------------
2475 // -- eax : the number of arguments (not including the receiver)
2476 // -- edx : the new target (checked to be a constructor)
2477 // -- edi : the constructor to call (checked to be a JSBoundFunction)
2478 // -----------------------------------
2479 __ AssertBoundFunction(edi);
2480
2481 // Push the [[BoundArguments]] onto the stack.
2482 Generate_PushBoundArguments(masm);
2483
2484 // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2485 {
2486 Label done;
2487 __ cmp(edi, edx);
2488 __ j(not_equal, &done, Label::kNear);
2489 __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2490 __ bind(&done);
2491 }
2492
2493 // Construct the [[BoundTargetFunction]] via the Construct builtin.
2494 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2495 __ mov(ecx, Operand::StaticVariable(
2496 ExternalReference(Builtins::kConstruct, masm->isolate())));
2497 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2498 __ jmp(ecx);
2499}
2500
2501
2502// static
2503void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2504 // ----------- S t a t e -------------
2505 // -- eax : the number of arguments (not including the receiver)
2506 // -- edi : the constructor to call (checked to be a JSProxy)
2507 // -- edx : the new target (either the same as the constructor or
2508 // the JSFunction on which new was invoked initially)
2509 // -----------------------------------
2510
2511 // Call into the Runtime for Proxy [[Construct]].
2512 __ PopReturnAddressTo(ecx);
2513 __ Push(edi);
2514 __ Push(edx);
2515 __ PushReturnAddressFrom(ecx);
2516 // Include the pushed new_target, constructor and the receiver.
2517 __ add(eax, Immediate(3));
2518 // Tail-call to the runtime.
2519 __ JumpToExternalReference(
2520 ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2521}
2522
2523
2524// static
2525void Builtins::Generate_Construct(MacroAssembler* masm) {
2526 // ----------- S t a t e -------------
2527 // -- eax : the number of arguments (not including the receiver)
2528 // -- edx : the new target (either the same as the constructor or
2529 // the JSFunction on which new was invoked initially)
2530 // -- edi : the constructor to call (can be any Object)
2531 // -----------------------------------
2532
2533 // Check if target is a Smi.
2534 Label non_constructor;
2535 __ JumpIfSmi(edi, &non_constructor, Label::kNear);
2536
2537 // Dispatch based on instance type.
2538 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2539 __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
2540 RelocInfo::CODE_TARGET);
2541
2542 // Check if target has a [[Construct]] internal method.
Ben Murdochda12d292016-06-02 14:46:10 +01002543 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
2544 Immediate(1 << Map::kIsConstructor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002545 __ j(zero, &non_constructor, Label::kNear);
2546
2547 // Only dispatch to bound functions after checking whether they are
2548 // constructors.
2549 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2550 __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
2551 RelocInfo::CODE_TARGET);
2552
2553 // Only dispatch to proxies after checking whether they are constructors.
2554 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2555 __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
2556 RelocInfo::CODE_TARGET);
2557
2558 // Called Construct on an exotic Object with a [[Construct]] internal method.
2559 {
2560 // Overwrite the original receiver with the (original) target.
2561 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2562 // Let the "call_as_constructor_delegate" take care of the rest.
2563 __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
2564 __ Jump(masm->isolate()->builtins()->CallFunction(),
2565 RelocInfo::CODE_TARGET);
2566 }
2567
2568 // Called Construct on an Object that doesn't have a [[Construct]] internal
2569 // method.
2570 __ bind(&non_constructor);
2571 __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
2572 RelocInfo::CODE_TARGET);
2573}
2574
Ben Murdochc5610432016-08-08 18:44:38 +01002575// static
2576void Builtins::Generate_AllocateInNewSpace(MacroAssembler* masm) {
2577 // ----------- S t a t e -------------
2578 // -- edx : requested object size (untagged)
2579 // -- esp[0] : return address
2580 // -----------------------------------
2581 __ SmiTag(edx);
2582 __ PopReturnAddressTo(ecx);
2583 __ Push(edx);
2584 __ PushReturnAddressFrom(ecx);
2585 __ Move(esi, Smi::FromInt(0));
2586 __ TailCallRuntime(Runtime::kAllocateInNewSpace);
2587}
2588
2589// static
2590void Builtins::Generate_AllocateInOldSpace(MacroAssembler* masm) {
2591 // ----------- S t a t e -------------
2592 // -- edx : requested object size (untagged)
2593 // -- esp[0] : return address
2594 // -----------------------------------
2595 __ SmiTag(edx);
2596 __ PopReturnAddressTo(ecx);
2597 __ Push(edx);
2598 __ Push(Smi::FromInt(AllocateTargetSpace::encode(OLD_SPACE)));
2599 __ PushReturnAddressFrom(ecx);
2600 __ Move(esi, Smi::FromInt(0));
2601 __ TailCallRuntime(Runtime::kAllocateInTargetSpace);
2602}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002603
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002604void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
2605 // ----------- S t a t e -------------
2606 // -- eax : actual number of arguments
2607 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002608 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002609 // -- edi : function (passed through to callee)
2610 // -----------------------------------
2611
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002612 Label invoke, dont_adapt_arguments, stack_overflow;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002613 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
2614
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002615 Label enough, too_few;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002616 __ cmp(eax, ebx);
2617 __ j(less, &too_few);
2618 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
2619 __ j(equal, &dont_adapt_arguments);
2620
2621 { // Enough parameters: Actual >= expected.
2622 __ bind(&enough);
2623 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002624 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002625
2626 // Copy receiver and all expected arguments.
2627 const int offset = StandardFrameConstants::kCallerSPOffset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002628 __ lea(edi, Operand(ebp, eax, times_4, offset));
2629 __ mov(eax, -1); // account for receiver
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002630
2631 Label copy;
2632 __ bind(&copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002633 __ inc(eax);
2634 __ push(Operand(edi, 0));
2635 __ sub(edi, Immediate(kPointerSize));
2636 __ cmp(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002637 __ j(less, &copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002638 // eax now contains the expected number of arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002639 __ jmp(&invoke);
2640 }
2641
2642 { // Too few parameters: Actual < expected.
2643 __ bind(&too_few);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002644
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002645 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002646 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
2647
2648 // Remember expected arguments in ecx.
2649 __ mov(ecx, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002650
2651 // Copy receiver and all actual arguments.
2652 const int offset = StandardFrameConstants::kCallerSPOffset;
2653 __ lea(edi, Operand(ebp, eax, times_4, offset));
2654 // ebx = expected - actual.
2655 __ sub(ebx, eax);
2656 // eax = -actual - 1
2657 __ neg(eax);
2658 __ sub(eax, Immediate(1));
2659
2660 Label copy;
2661 __ bind(&copy);
2662 __ inc(eax);
2663 __ push(Operand(edi, 0));
2664 __ sub(edi, Immediate(kPointerSize));
2665 __ test(eax, eax);
2666 __ j(not_zero, &copy);
2667
2668 // Fill remaining expected arguments with undefined values.
2669 Label fill;
2670 __ bind(&fill);
2671 __ inc(eax);
2672 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
2673 __ cmp(eax, ebx);
2674 __ j(less, &fill);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002675
2676 // Restore expected arguments.
2677 __ mov(eax, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002678 }
2679
2680 // Call the entry point.
2681 __ bind(&invoke);
2682 // Restore function pointer.
Ben Murdochda12d292016-06-02 14:46:10 +01002683 __ mov(edi, Operand(ebp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002684 // eax : expected number of arguments
2685 // edx : new target (passed through to callee)
2686 // edi : function (passed through to callee)
2687 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2688 __ call(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002689
2690 // Store offset of return address for deoptimizer.
2691 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
2692
2693 // Leave frame and return.
2694 LeaveArgumentsAdaptorFrame(masm);
2695 __ ret(0);
2696
2697 // -------------------------------------------
2698 // Dont adapt arguments.
2699 // -------------------------------------------
2700 __ bind(&dont_adapt_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002701 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2702 __ jmp(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002703
2704 __ bind(&stack_overflow);
2705 {
2706 FrameScope frame(masm, StackFrame::MANUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002707 __ CallRuntime(Runtime::kThrowStackOverflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002708 __ int3();
2709 }
2710}
2711
2712
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002713static void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
2714 Register function_template_info,
2715 Register scratch0, Register scratch1,
2716 Label* receiver_check_failed) {
2717 // If there is no signature, return the holder.
2718 __ CompareRoot(FieldOperand(function_template_info,
2719 FunctionTemplateInfo::kSignatureOffset),
2720 Heap::kUndefinedValueRootIndex);
2721 Label receiver_check_passed;
2722 __ j(equal, &receiver_check_passed, Label::kNear);
2723
2724 // Walk the prototype chain.
2725 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2726 Label prototype_loop_start;
2727 __ bind(&prototype_loop_start);
2728
2729 // Get the constructor, if any.
2730 __ GetMapConstructor(scratch0, scratch0, scratch1);
2731 __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE);
2732 Label next_prototype;
2733 __ j(not_equal, &next_prototype, Label::kNear);
2734
2735 // Get the constructor's signature.
2736 __ mov(scratch0,
2737 FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset));
2738 __ mov(scratch0,
2739 FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset));
2740
2741 // Loop through the chain of inheriting function templates.
2742 Label function_template_loop;
2743 __ bind(&function_template_loop);
2744
2745 // If the signatures match, we have a compatible receiver.
2746 __ cmp(scratch0, FieldOperand(function_template_info,
2747 FunctionTemplateInfo::kSignatureOffset));
2748 __ j(equal, &receiver_check_passed, Label::kNear);
2749
2750 // If the current type is not a FunctionTemplateInfo, load the next prototype
2751 // in the chain.
2752 __ JumpIfSmi(scratch0, &next_prototype, Label::kNear);
2753 __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1);
2754 __ j(not_equal, &next_prototype, Label::kNear);
2755
2756 // Otherwise load the parent function template and iterate.
2757 __ mov(scratch0,
2758 FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset));
2759 __ jmp(&function_template_loop, Label::kNear);
2760
2761 // Load the next prototype.
2762 __ bind(&next_prototype);
2763 __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002764 __ test(FieldOperand(receiver, Map::kBitField3Offset),
2765 Immediate(Map::HasHiddenPrototype::kMask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002766 __ j(zero, receiver_check_failed);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002767
2768 __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset));
2769 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002770 // Iterate.
2771 __ jmp(&prototype_loop_start, Label::kNear);
2772
2773 __ bind(&receiver_check_passed);
2774}
2775
2776
2777void Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
2778 // ----------- S t a t e -------------
2779 // -- eax : number of arguments (not including the receiver)
2780 // -- edi : callee
2781 // -- esi : context
2782 // -- esp[0] : return address
2783 // -- esp[4] : last argument
2784 // -- ...
2785 // -- esp[eax * 4] : first argument
2786 // -- esp[(eax + 1) * 4] : receiver
2787 // -----------------------------------
2788
2789 // Load the FunctionTemplateInfo.
2790 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2791 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
2792
2793 // Do the compatible receiver check.
2794 Label receiver_check_failed;
2795 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize));
2796 __ Push(eax);
2797 CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed);
2798 __ Pop(eax);
2799 // Get the callback offset from the FunctionTemplateInfo, and jump to the
2800 // beginning of the code.
2801 __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset));
2802 __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset));
2803 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
2804 __ jmp(edx);
2805
2806 // Compatible receiver check failed: pop return address, arguments and
2807 // receiver and throw an Illegal Invocation exception.
2808 __ bind(&receiver_check_failed);
2809 __ Pop(eax);
2810 __ PopReturnAddressTo(ebx);
2811 __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize));
2812 __ add(esp, eax);
2813 __ PushReturnAddressFrom(ebx);
2814 {
2815 FrameScope scope(masm, StackFrame::INTERNAL);
2816 __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
2817 }
2818}
2819
2820
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002821void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
2822 // Lookup the function in the JavaScript frame.
2823 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2824 {
2825 FrameScope scope(masm, StackFrame::INTERNAL);
2826 // Pass function as argument.
2827 __ push(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002828 __ CallRuntime(Runtime::kCompileForOnStackReplacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002829 }
2830
2831 Label skip;
2832 // If the code object is null, just return to the unoptimized code.
2833 __ cmp(eax, Immediate(0));
2834 __ j(not_equal, &skip, Label::kNear);
2835 __ ret(0);
2836
2837 __ bind(&skip);
2838
2839 // Load deoptimization data from the code object.
2840 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
2841
2842 // Load the OSR entrypoint offset from the deoptimization data.
2843 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
2844 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
2845 __ SmiUntag(ebx);
2846
2847 // Compute the target address = code_obj + header_size + osr_offset
2848 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
2849
2850 // Overwrite the return address on the stack.
2851 __ mov(Operand(esp, 0), eax);
2852
2853 // And "return" to the OSR entry point of the function.
2854 __ ret(0);
2855}
2856
2857
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002858#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002859} // namespace internal
2860} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002861
2862#endif // V8_TARGET_ARCH_X87