1 // 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.
5 #if V8_TARGET_ARCH_IA32
7 #include "src/code-factory.h"
8 #include "src/codegen.h"
9 #include "src/deoptimizer.h"
10 #include "src/full-codegen/full-codegen.h"
11 #include "src/ia32/frames-ia32.h"
17 #define __ ACCESS_MASM(masm)
20 void Builtins::Generate_Adaptor(MacroAssembler* masm,
22 BuiltinExtraArguments extra_args) {
23 // ----------- S t a t e -------------
24 // -- eax : number of arguments excluding receiver
25 // -- edi : called function (only guaranteed when
26 // extra_args requires it)
28 // -- esp[0] : return address
29 // -- esp[4] : last argument
31 // -- esp[4 * argc] : first argument (argc == eax)
32 // -- esp[4 * (argc +1)] : receiver
33 // -----------------------------------
35 // Insert extra arguments.
36 int num_extra_args = 0;
37 if (extra_args == NEEDS_CALLED_FUNCTION) {
39 Register scratch = ebx;
40 __ pop(scratch); // Save return address.
42 __ push(scratch); // Restore return address.
44 DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
47 // JumpToExternalReference expects eax to contain the number of arguments
48 // including the receiver and the extra arguments.
49 __ add(eax, Immediate(num_extra_args + 1));
50 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
54 static void CallRuntimePassFunction(
55 MacroAssembler* masm, Runtime::FunctionId function_id) {
56 FrameScope scope(masm, StackFrame::INTERNAL);
57 // Push a copy of the function.
59 // Function is also the parameter to the runtime call.
62 __ CallRuntime(function_id, 1);
68 static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
69 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
70 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kCodeOffset));
71 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
76 static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
77 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
82 void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
83 // Checking whether the queued function is ready for install is optional,
84 // since we come across interrupts and stack checks elsewhere. However,
85 // not checking may delay installing ready functions, and always checking
86 // would be quite expensive. A good compromise is to first check against
87 // stack limit as a cue for an interrupt signal.
89 ExternalReference stack_limit =
90 ExternalReference::address_of_stack_limit(masm->isolate());
91 __ cmp(esp, Operand::StaticVariable(stack_limit));
92 __ j(above_equal, &ok, Label::kNear);
94 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
95 GenerateTailCallToReturnedCode(masm);
98 GenerateTailCallToSharedCode(masm);
102 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
103 bool is_api_function) {
104 // ----------- S t a t e -------------
105 // -- eax: number of arguments
106 // -- edi: constructor function
107 // -- ebx: allocation site or undefined
108 // -- edx: original constructor
109 // -----------------------------------
111 // Enter a construct frame.
113 FrameScope scope(masm, StackFrame::CONSTRUCT);
115 // Preserve the incoming parameters on the stack.
116 __ AssertUndefinedOrAllocationSite(ebx);
123 // Try to allocate the object without transitioning into C code. If any of
124 // the preconditions is not met, the code bails out to the runtime call.
125 Label rt_call, allocated;
126 if (FLAG_inline_new) {
127 ExternalReference debug_step_in_fp =
128 ExternalReference::debug_step_in_fp_address(masm->isolate());
129 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
130 __ j(not_equal, &rt_call);
132 // Fall back to runtime if the original constructor and function differ.
134 __ j(not_equal, &rt_call);
136 // Verified that the constructor is a JSFunction.
137 // Load the initial map and verify that it is in fact a map.
139 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
140 // Will both indicate a NULL and a Smi
141 __ JumpIfSmi(eax, &rt_call);
143 // eax: initial map (if proven valid below)
144 __ CmpObjectType(eax, MAP_TYPE, ebx);
145 __ j(not_equal, &rt_call);
147 // Check that the constructor is not constructing a JSFunction (see
148 // comments in Runtime_NewObject in runtime.cc). In which case the
149 // initial map's instance type would be JS_FUNCTION_TYPE.
152 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
153 __ j(equal, &rt_call);
155 if (!is_api_function) {
157 // The code below relies on these assumptions.
158 STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
159 // Check if slack tracking is enabled.
160 __ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
161 __ shr(esi, Map::Counter::kShift);
162 __ cmp(esi, Map::kSlackTrackingCounterEnd);
163 __ j(less, &allocate);
164 // Decrease generous allocation count.
165 __ sub(FieldOperand(eax, Map::kBitField3Offset),
166 Immediate(1 << Map::Counter::kShift));
168 __ cmp(esi, Map::kSlackTrackingCounterEnd);
169 __ j(not_equal, &allocate);
175 __ push(edi); // constructor
176 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
181 __ mov(esi, Map::kSlackTrackingCounterEnd - 1);
186 // Now allocate the JSObject on the heap.
189 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
190 __ shl(edi, kPointerSizeLog2);
192 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
194 Factory* factory = masm->isolate()->factory();
196 // Allocated the JSObject, now initialize the fields.
199 // edi: start of next object
200 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
201 __ mov(ecx, factory->empty_fixed_array());
202 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
203 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
204 // Set extra fields in the newly allocated object.
207 // edi: start of next object
208 // esi: slack tracking counter (non-API function case)
209 __ mov(edx, factory->undefined_value());
210 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
211 if (!is_api_function) {
212 Label no_inobject_slack_tracking;
214 // Check if slack tracking is enabled.
215 __ cmp(esi, Map::kSlackTrackingCounterEnd);
216 __ j(less, &no_inobject_slack_tracking);
218 // Allocate object with a slack.
222 eax, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset));
223 __ movzx_b(eax, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
226 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
227 // esi: offset of first field after pre-allocated fields
228 if (FLAG_debug_code) {
230 __ Assert(less_equal,
231 kUnexpectedNumberOfPreAllocatedPropertyFields);
233 __ InitializeFieldsWithFiller(ecx, esi, edx);
234 __ mov(edx, factory->one_pointer_filler_map());
235 // Fill the remaining fields with one pointer filler map.
237 __ bind(&no_inobject_slack_tracking);
240 __ InitializeFieldsWithFiller(ecx, edi, edx);
242 // Add the object tag to make the JSObject real, so that we can continue
243 // and jump into the continuation code at any time from now on.
244 // ebx: JSObject (untagged)
245 __ or_(ebx, Immediate(kHeapObjectTag));
247 // Continue with JSObject being successfully allocated
248 // ebx: JSObject (tagged)
252 // Allocate the new receiver object using the runtime call.
253 // edx: original constructor
255 int offset = kPointerSize;
257 // Must restore esi (context) and edi (constructor) before calling
259 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
260 __ mov(edi, Operand(esp, offset));
261 __ push(edi); // argument 2/1: constructor function
262 __ push(edx); // argument 3/2: original constructor
263 __ CallRuntime(Runtime::kNewObject, 2);
264 __ mov(ebx, eax); // store result in ebx
266 // New object allocated.
267 // ebx: newly allocated object
270 // Restore the parameters.
271 __ pop(edx); // new.target
272 __ pop(edi); // Constructor function.
274 // Retrieve smi-tagged arguments count from the stack.
275 __ mov(eax, Operand(esp, 0));
278 // Push new.target onto the construct frame. This is stored just below the
279 // receiver on the stack.
282 // Push the allocated receiver to the stack. We need two copies
283 // because we may have to return the original one and the calling
284 // conventions dictate that the called function pops the receiver.
288 // Set up pointer to last argument.
289 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
291 // Copy arguments and receiver to the expression stack.
296 __ push(Operand(ebx, ecx, times_4, 0));
299 __ j(greater_equal, &loop);
301 // Call the function.
302 if (is_api_function) {
303 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
305 masm->isolate()->builtins()->HandleApiCallConstruct();
306 __ call(code, RelocInfo::CODE_TARGET);
308 ParameterCount actual(eax);
309 __ InvokeFunction(edi, actual, CALL_FUNCTION,
313 // Store offset of return address for deoptimizer.
314 if (!is_api_function) {
315 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
318 // Restore context from the frame.
319 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
321 // If the result is an object (in the ECMA sense), we should get rid
322 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
324 Label use_receiver, exit;
326 // If the result is a smi, it is *not* an object in the ECMA sense.
327 __ JumpIfSmi(eax, &use_receiver);
329 // If the type of the result (stored in its map) is less than
330 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
331 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
332 __ j(above_equal, &exit);
334 // Throw away the result of the constructor invocation and use the
335 // on-stack receiver as the result.
336 __ bind(&use_receiver);
337 __ mov(eax, Operand(esp, 0));
339 // Restore the arguments count and leave the construct frame. The arguments
340 // count is stored below the reciever and the new.target.
342 __ mov(ebx, Operand(esp, 2 * kPointerSize));
344 // Leave construct frame.
347 // Remove caller arguments from the stack and return.
348 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
350 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
352 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
357 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
358 Generate_JSConstructStubHelper(masm, false);
362 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
363 Generate_JSConstructStubHelper(masm, true);
367 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
368 // ----------- S t a t e -------------
369 // -- eax: number of arguments
370 // -- edi: constructor function
371 // -- ebx: allocation site or undefined
372 // -- edx: original constructor
373 // -----------------------------------
376 FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
378 // Preserve allocation site.
379 __ AssertUndefinedOrAllocationSite(ebx);
382 // Preserve actual arguments count.
390 // receiver is the hole.
391 __ push(Immediate(masm->isolate()->factory()->the_hole_value()));
393 // Set up pointer to last argument.
394 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
396 // Copy arguments and receiver to the expression stack.
401 __ push(Operand(ebx, ecx, times_4, 0));
404 __ j(greater_equal, &loop);
408 ExternalReference debug_step_in_fp =
409 ExternalReference::debug_step_in_fp_address(masm->isolate());
410 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
411 __ j(equal, &skip_step_in);
416 __ CallRuntime(Runtime::kHandleStepInForDerivedConstructors, 1);
420 __ bind(&skip_step_in);
423 ParameterCount actual(eax);
424 __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
426 // Restore context from the frame.
427 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
429 // Get arguments count, skipping over new.target.
430 __ mov(ebx, Operand(esp, kPointerSize));
433 __ pop(ecx); // Return address.
434 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));
440 enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
443 // Clobbers ecx, edx, edi; preserves all other registers.
444 static void Generate_CheckStackOverflow(MacroAssembler* masm,
445 const int calleeOffset,
446 IsTagged eax_is_tagged) {
447 // eax : the number of items to be pushed to the stack
449 // Check the stack for overflow. We are not trying to catch
450 // interruptions (e.g. debug break and preemption) here, so the "real stack
451 // limit" is checked.
453 ExternalReference real_stack_limit =
454 ExternalReference::address_of_real_stack_limit(masm->isolate());
455 __ mov(edi, Operand::StaticVariable(real_stack_limit));
456 // Make ecx the space we have left. The stack might already be overflowed
457 // here which will cause ecx to become negative.
460 // Make edx the space we need for the array when it is unrolled onto the
463 int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
464 __ shl(edx, kPointerSizeLog2 - smi_tag);
465 // Check if the arguments will overflow the stack.
467 __ j(greater, &okay); // Signed comparison.
469 // Out of stack space.
470 __ push(Operand(ebp, calleeOffset)); // push this
471 if (eax_is_tagged == kEaxIsUntaggedInt) {
475 __ CallRuntime(Runtime::kThrowStackOverflow, 0);
481 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
483 ProfileEntryHookStub::MaybeCallEntryHook(masm);
485 // Clear the context before we push it when entering the internal frame.
486 __ Move(esi, Immediate(0));
489 FrameScope scope(masm, StackFrame::INTERNAL);
491 // Load the previous frame pointer (ebx) to access C arguments
492 __ mov(ebx, Operand(ebp, 0));
494 // Get the function from the frame and setup the context.
495 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
496 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
498 // Push the function and the receiver onto the stack.
500 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
502 // Load the number of arguments and setup pointer to the arguments.
503 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
504 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
506 // Check if we have enough stack space to push all arguments.
507 // The function is the first thing that was pushed above after entering
508 // the internal frame.
509 const int kFunctionOffset =
510 InternalFrameConstants::kCodeOffset - kPointerSize;
511 // Expects argument count in eax. Clobbers ecx, edx, edi.
512 Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsUntaggedInt);
514 // Copy arguments to the stack in a loop.
516 __ Move(ecx, Immediate(0));
519 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
520 __ push(Operand(edx, 0)); // dereference handle
524 __ j(not_equal, &loop);
526 // Get the function from the stack and call it.
527 // kPointerSize for the receiver.
528 __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
532 // No type feedback cell is available
533 __ mov(ebx, masm->isolate()->factory()->undefined_value());
534 CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
537 __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
540 // Exit the internal frame. Notice that this also removes the empty.
541 // context and the function left on the stack by the code
544 __ ret(kPointerSize); // Remove receiver.
548 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
549 Generate_JSEntryTrampolineHelper(masm, false);
553 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
554 Generate_JSEntryTrampolineHelper(masm, true);
558 // Generate code for entering a JS function with the interpreter.
559 // On entry to the function the receiver and arguments have been pushed on the
560 // stack left to right. The actual argument count matches the formal parameter
561 // count expected by the function.
563 // The live registers are:
564 // o edi: the JS function object being called
565 // o esi: our context
566 // o ebp: the caller's frame pointer
567 // o esp: stack pointer (pointing to return address)
569 // The function builds a JS frame. Please see JavaScriptFrameConstants in
570 // frames-ia32.h for its layout.
571 // TODO(rmcilroy): We will need to include the current bytecode pointer in the
573 void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
574 // Open a frame scope to indicate that there is a frame on the stack. The
575 // MANUAL indicates that the scope shouldn't actually generate code to set up
576 // the frame (that is done below).
577 FrameScope frame_scope(masm, StackFrame::MANUAL);
578 __ push(ebp); // Caller's frame pointer.
580 __ push(esi); // Callee's context.
581 __ push(edi); // Callee's JS function.
583 // Get the bytecode array from the function object and load the pointer to the
584 // first entry into edi (InterpreterBytecodeRegister).
585 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
586 __ mov(kInterpreterBytecodeArrayRegister,
587 FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
589 if (FLAG_debug_code) {
590 // Check function data field is actually a BytecodeArray object.
591 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
592 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
594 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
597 // Allocate the local and temporary register file on the stack.
599 // Load frame size from the BytecodeArray object.
600 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
601 BytecodeArray::kFrameSizeOffset));
603 // Do a stack check to ensure we don't go over the limit.
607 ExternalReference stack_limit =
608 ExternalReference::address_of_real_stack_limit(masm->isolate());
609 __ cmp(ecx, Operand::StaticVariable(stack_limit));
610 __ j(above_equal, &ok);
611 __ CallRuntime(Runtime::kThrowStackOverflow, 0);
614 // If ok, push undefined as the initial value for all register file entries.
617 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
619 __ bind(&loop_header);
620 // TODO(rmcilroy): Consider doing more than one push per loop iteration.
622 // Continue loop if not done.
623 __ bind(&loop_check);
624 __ sub(ebx, Immediate(kPointerSize));
625 __ j(greater_equal, &loop_header);
628 // TODO(rmcilroy): List of things not currently dealt with here but done in
629 // fullcodegen's prologue:
630 // - Support profiler (specifically profiling_counter).
631 // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
632 // - Allow simulator stop operations if FLAG_stop_at is set.
633 // - Deal with sloppy mode functions which need to replace the
634 // receiver with the global proxy when called as functions (without an
635 // explicit receiver object).
636 // - Code aging of the BytecodeArray object.
637 // - Supporting FLAG_trace.
639 // The following items are also not done here, and will probably be done using
640 // explicit bytecodes instead:
641 // - Allocating a new local context if applicable.
642 // - Setting up a local binding to the this function, which is used in
643 // derived constructors with super calls.
644 // - Setting new.target if required.
645 // - Dealing with REST parameters (only if
646 // https://codereview.chromium.org/1235153006 doesn't land by then).
647 // - Dealing with argument objects.
649 // Perform stack guard check.
652 ExternalReference stack_limit =
653 ExternalReference::address_of_stack_limit(masm->isolate());
654 __ cmp(esp, Operand::StaticVariable(stack_limit));
655 __ j(above_equal, &ok);
656 __ CallRuntime(Runtime::kStackGuard, 0);
660 // Load accumulator, register file, bytecode offset, dispatch table into
662 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
663 __ mov(kInterpreterRegisterFileRegister, ebp);
665 kInterpreterRegisterFileRegister,
666 Immediate(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
667 __ mov(kInterpreterBytecodeOffsetRegister,
668 Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
669 // Since the dispatch table root might be set after builtins are generated,
670 // load directly from the roots table.
671 __ LoadRoot(kInterpreterDispatchTableRegister,
672 Heap::kInterpreterTableRootIndex);
673 __ add(kInterpreterDispatchTableRegister,
674 Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
676 // Push context as a stack located parameter to the bytecode handler.
677 DCHECK_EQ(-1, kInterpreterContextSpillSlot);
680 // Dispatch to the first bytecode handler for the function.
681 __ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
682 kInterpreterBytecodeOffsetRegister, times_1, 0));
683 __ mov(esi, Operand(kInterpreterDispatchTableRegister, esi,
684 times_pointer_size, 0));
685 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
686 // and header removal.
687 __ add(esi, Immediate(Code::kHeaderSize - kHeapObjectTag));
692 void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
693 // TODO(rmcilroy): List of things not currently dealt with here but done in
694 // fullcodegen's EmitReturnSequence.
695 // - Supporting FLAG_trace for Runtime::TraceExit.
696 // - Support profiler (specifically decrementing profiling_counter
697 // appropriately and calling out to HandleInterrupts if necessary).
699 // The return value is in accumulator, which is already in rax.
701 // Leave the frame (also dropping the register file).
704 // Drop receiver + arguments and return.
705 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
706 BytecodeArray::kParameterSizeOffset));
714 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
715 CallRuntimePassFunction(masm, Runtime::kCompileLazy);
716 GenerateTailCallToReturnedCode(masm);
721 static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
722 FrameScope scope(masm, StackFrame::INTERNAL);
723 // Push a copy of the function.
725 // Function is also the parameter to the runtime call.
727 // Whether to compile in a background thread.
728 __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
730 __ CallRuntime(Runtime::kCompileOptimized, 2);
736 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
737 CallCompileOptimized(masm, false);
738 GenerateTailCallToReturnedCode(masm);
742 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
743 CallCompileOptimized(masm, true);
744 GenerateTailCallToReturnedCode(masm);
748 static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
749 // For now, we are relying on the fact that make_code_young doesn't do any
750 // garbage collection which allows us to save/restore the registers without
751 // worrying about which of them contain pointers. We also don't build an
752 // internal frame to make the code faster, since we shouldn't have to do stack
753 // crawls in MakeCodeYoung. This seems a bit fragile.
755 // Re-execute the code that was patched back to the young age when
757 __ sub(Operand(esp, 0), Immediate(5));
759 __ mov(eax, Operand(esp, 8 * kPointerSize));
761 FrameScope scope(masm, StackFrame::MANUAL);
762 __ PrepareCallCFunction(2, ebx);
763 __ mov(Operand(esp, 1 * kPointerSize),
764 Immediate(ExternalReference::isolate_address(masm->isolate())));
765 __ mov(Operand(esp, 0), eax);
767 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
773 #define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
774 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
775 MacroAssembler* masm) { \
776 GenerateMakeCodeYoungAgainCommon(masm); \
778 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
779 MacroAssembler* masm) { \
780 GenerateMakeCodeYoungAgainCommon(masm); \
782 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
783 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
786 void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
787 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
788 // that make_code_young doesn't do any garbage collection which allows us to
789 // save/restore the registers without worrying about which of them contain
792 __ mov(eax, Operand(esp, 8 * kPointerSize));
793 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
795 FrameScope scope(masm, StackFrame::MANUAL);
796 __ PrepareCallCFunction(2, ebx);
797 __ mov(Operand(esp, 1 * kPointerSize),
798 Immediate(ExternalReference::isolate_address(masm->isolate())));
799 __ mov(Operand(esp, 0), eax);
801 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
806 // Perform prologue operations usually performed by the young code stub.
807 __ pop(eax); // Pop return address into scratch register.
808 __ push(ebp); // Caller's frame pointer.
810 __ push(esi); // Callee's context.
811 __ push(edi); // Callee's JS Function.
812 __ push(eax); // Push return address after frame prologue.
814 // Jump to point after the code-age stub.
819 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
820 GenerateMakeCodeYoungAgainCommon(masm);
824 void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
825 Generate_MarkCodeAsExecutedOnce(masm);
829 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
830 SaveFPRegsMode save_doubles) {
831 // Enter an internal frame.
833 FrameScope scope(masm, StackFrame::INTERNAL);
835 // Preserve registers across notification, this is important for compiled
836 // stubs that tail call the runtime on deopts passing their parameters in
839 __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
841 // Tear down internal frame.
844 __ pop(MemOperand(esp, 0)); // Ignore state offset
845 __ ret(0); // Return to IC Miss stub, continuation still on stack.
849 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
850 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
854 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
855 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
859 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
860 Deoptimizer::BailoutType type) {
862 FrameScope scope(masm, StackFrame::INTERNAL);
864 // Pass deoptimization type to the runtime system.
865 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
866 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
868 // Tear down internal frame.
871 // Get the full codegen state from the stack and untag it.
872 __ mov(ecx, Operand(esp, 1 * kPointerSize));
875 // Switch on the state.
876 Label not_no_registers, not_tos_eax;
877 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
878 __ j(not_equal, ¬_no_registers, Label::kNear);
879 __ ret(1 * kPointerSize); // Remove state.
881 __ bind(¬_no_registers);
882 __ mov(eax, Operand(esp, 2 * kPointerSize));
883 __ cmp(ecx, FullCodeGenerator::TOS_REG);
884 __ j(not_equal, ¬_tos_eax, Label::kNear);
885 __ ret(2 * kPointerSize); // Remove state, eax.
887 __ bind(¬_tos_eax);
888 __ Abort(kNoCasesLeft);
892 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
893 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
897 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
898 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
902 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
903 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
908 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
910 // esp[0] : Return address
911 // esp[8] : Argument n
912 // esp[16] : Argument n-1
914 // esp[8 * n] : Argument 1
915 // esp[8 * (n + 1)] : Receiver (callable to call)
917 // eax contains the number of arguments, n, not counting the receiver.
919 // 1. Make sure we have at least one argument.
923 __ j(not_zero, &done, Label::kNear);
924 __ PopReturnAddressTo(ebx);
925 __ PushRoot(Heap::kUndefinedValueRootIndex);
926 __ PushReturnAddressFrom(ebx);
931 // 2. Get the callable to call (passed as receiver) from the stack.
932 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
934 // 3. Shift arguments and return address one slot down on the stack
935 // (overwriting the original receiver). Adjust argument count to make
936 // the original first argument the new receiver.
941 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
942 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
944 __ j(not_sign, &loop); // While non-negative (to copy return address).
945 __ pop(ebx); // Discard copy of return address.
946 __ dec(eax); // One fewer argument (first argument is new receiver).
949 // 4. Call the callable.
950 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
954 static void Generate_PushAppliedArguments(MacroAssembler* masm,
955 const int vectorOffset,
956 const int argumentsOffset,
957 const int indexOffset,
958 const int limitOffset) {
959 // Copy all arguments from the array to the stack.
961 Register receiver = LoadDescriptor::ReceiverRegister();
962 Register key = LoadDescriptor::NameRegister();
963 Register slot = LoadDescriptor::SlotRegister();
964 Register vector = LoadWithVectorDescriptor::VectorRegister();
965 __ mov(key, Operand(ebp, indexOffset));
968 __ mov(receiver, Operand(ebp, argumentsOffset)); // load arguments
970 // Use inline caching to speed up access to arguments.
971 int slot_index = TypeFeedbackVector::PushAppliedArgumentsIndex();
972 __ mov(slot, Immediate(Smi::FromInt(slot_index)));
973 __ mov(vector, Operand(ebp, vectorOffset));
975 KeyedLoadICStub(masm->isolate(), LoadICState(kNoExtraICState)).GetCode();
976 __ call(ic, RelocInfo::CODE_TARGET);
977 // It is important that we do not have a test instruction after the
978 // call. A test instruction after the call is used to indicate that
979 // we have generated an inline version of the keyed load. In this
980 // case, we know that we are not generating a test instruction next.
982 // Push the nth argument.
985 // Update the index on the stack and in register key.
986 __ mov(key, Operand(ebp, indexOffset));
987 __ add(key, Immediate(1 << kSmiTagSize));
988 __ mov(Operand(ebp, indexOffset), key);
991 __ cmp(key, Operand(ebp, limitOffset));
992 __ j(not_equal, &loop);
994 // On exit, the pushed arguments count is in eax, untagged
1000 // Used by FunctionApply and ReflectApply
1001 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
1002 const int kFormalParameters = targetIsArgument ? 3 : 2;
1003 const int kStackSize = kFormalParameters + 1;
1006 // esp : return address
1007 // esp[4] : arguments
1008 // esp[8] : receiver ("this")
1009 // esp[12] : function
1011 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1013 // ebp : Old base pointer
1014 // ebp[4] : return address
1015 // ebp[8] : function arguments
1016 // ebp[12] : receiver
1017 // ebp[16] : function
1018 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
1019 static const int kReceiverOffset = kArgumentsOffset + kPointerSize;
1020 static const int kFunctionOffset = kReceiverOffset + kPointerSize;
1021 static const int kVectorOffset =
1022 InternalFrameConstants::kCodeOffset - 1 * kPointerSize;
1025 __ mov(edi, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1026 __ mov(edi, FieldOperand(edi, SharedFunctionInfo::kFeedbackVectorOffset));
1029 __ push(Operand(ebp, kFunctionOffset)); // push this
1030 __ push(Operand(ebp, kArgumentsOffset)); // push arguments
1031 if (targetIsArgument) {
1032 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX,
1035 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION);
1038 Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsSmiTagged);
1040 // Push current index and limit.
1041 const int kLimitOffset = kVectorOffset - 1 * kPointerSize;
1042 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
1043 __ Push(eax); // limit
1044 __ Push(Immediate(0)); // index
1045 __ Push(Operand(ebp, kReceiverOffset)); // receiver
1047 // Loop over the arguments array, pushing each value to the stack
1048 Generate_PushAppliedArguments(masm, kVectorOffset, kArgumentsOffset,
1049 kIndexOffset, kLimitOffset);
1051 // Call the callable.
1052 // TODO(bmeurer): This should be a tail call according to ES6.
1053 __ mov(edi, Operand(ebp, kFunctionOffset));
1054 __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1056 // Leave internal frame.
1058 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments
1062 // Used by ReflectConstruct
1063 static void Generate_ConstructHelper(MacroAssembler* masm) {
1064 const int kFormalParameters = 3;
1065 const int kStackSize = kFormalParameters + 1;
1068 // esp : return address
1069 // esp[4] : original constructor (new.target)
1070 // esp[8] : arguments
1071 // esp[16] : constructor
1073 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1075 // ebp : Old base pointer
1076 // ebp[4] : return address
1077 // ebp[8] : original constructor (new.target)
1078 // ebp[12] : arguments
1079 // ebp[16] : constructor
1080 static const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
1081 static const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
1082 static const int kFunctionOffset = kArgumentsOffset + kPointerSize;
1083 static const int kVectorOffset =
1084 InternalFrameConstants::kCodeOffset - 1 * kPointerSize;
1087 __ mov(edi, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1088 __ mov(edi, FieldOperand(edi, SharedFunctionInfo::kFeedbackVectorOffset));
1091 // If newTarget is not supplied, set it to constructor
1092 Label validate_arguments;
1093 __ mov(eax, Operand(ebp, kNewTargetOffset));
1094 __ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
1095 __ j(not_equal, &validate_arguments, Label::kNear);
1096 __ mov(eax, Operand(ebp, kFunctionOffset));
1097 __ mov(Operand(ebp, kNewTargetOffset), eax);
1099 // Validate arguments
1100 __ bind(&validate_arguments);
1101 __ push(Operand(ebp, kFunctionOffset));
1102 __ push(Operand(ebp, kArgumentsOffset));
1103 __ push(Operand(ebp, kNewTargetOffset));
1104 __ InvokeBuiltin(Context::REFLECT_CONSTRUCT_PREPARE_BUILTIN_INDEX,
1107 Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsSmiTagged);
1109 // Push current index and limit.
1110 const int kLimitOffset = kVectorOffset - 1 * kPointerSize;
1111 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
1112 __ Push(eax); // limit
1113 __ push(Immediate(0)); // index
1114 // Push the constructor function as callee.
1115 __ push(Operand(ebp, kFunctionOffset));
1117 // Loop over the arguments array, pushing each value to the stack
1118 Generate_PushAppliedArguments(masm, kVectorOffset, kArgumentsOffset,
1119 kIndexOffset, kLimitOffset);
1121 // Use undefined feedback vector
1122 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
1123 __ mov(edi, Operand(ebp, kFunctionOffset));
1124 __ mov(ecx, Operand(ebp, kNewTargetOffset));
1126 // Call the function.
1127 CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
1128 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
1130 // Leave internal frame.
1132 // remove this, target, arguments, and newTarget
1133 __ ret(kStackSize * kPointerSize);
1137 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1138 Generate_ApplyHelper(masm, false);
1142 void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1143 Generate_ApplyHelper(masm, true);
1147 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1148 Generate_ConstructHelper(masm);
1152 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1153 // ----------- S t a t e -------------
1155 // -- esp[0] : return address
1156 // -- esp[4] : last argument
1157 // -----------------------------------
1158 Label generic_array_code;
1160 // Get the InternalArray function.
1161 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1163 if (FLAG_debug_code) {
1164 // Initial map for the builtin InternalArray function should be a map.
1165 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1166 // Will both indicate a NULL and a Smi.
1167 __ test(ebx, Immediate(kSmiTagMask));
1168 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1169 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1170 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1173 // Run the native code for the InternalArray function called as a normal
1176 InternalArrayConstructorStub stub(masm->isolate());
1177 __ TailCallStub(&stub);
1181 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1182 // ----------- S t a t e -------------
1184 // -- esp[0] : return address
1185 // -- esp[4] : last argument
1186 // -----------------------------------
1187 Label generic_array_code;
1189 // Get the Array function.
1190 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
1193 if (FLAG_debug_code) {
1194 // Initial map for the builtin Array function should be a map.
1195 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1196 // Will both indicate a NULL and a Smi.
1197 __ test(ebx, Immediate(kSmiTagMask));
1198 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1199 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1200 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1203 // Run the native code for the Array function called as a normal function.
1205 __ mov(ebx, masm->isolate()->factory()->undefined_value());
1206 ArrayConstructorStub stub(masm->isolate());
1207 __ TailCallStub(&stub);
1212 void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
1213 // ----------- S t a t e -------------
1214 // -- eax : number of arguments
1215 // -- edi : constructor function
1216 // -- esp[0] : return address
1217 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1218 // -- esp[(argc + 1) * 4] : receiver
1219 // -----------------------------------
1221 // 1. Load the first argument into eax and get rid of the rest (including the
1226 __ j(zero, &no_arguments, Label::kNear);
1227 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1228 __ PopReturnAddressTo(ecx);
1229 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1230 __ PushReturnAddressFrom(ecx);
1234 // 2a. At least one argument, return eax if it's a string, otherwise
1235 // dispatch to appropriate conversion.
1236 Label to_string, symbol_descriptive_string;
1238 __ JumpIfSmi(eax, &to_string, Label::kNear);
1239 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
1240 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
1241 __ j(above, &to_string, Label::kNear);
1242 __ j(equal, &symbol_descriptive_string, Label::kNear);
1246 // 2b. No arguments, return the empty string (and pop the receiver).
1247 __ bind(&no_arguments);
1249 __ LoadRoot(eax, Heap::kempty_stringRootIndex);
1250 __ ret(1 * kPointerSize);
1253 // 3a. Convert eax to a string.
1254 __ bind(&to_string);
1256 ToStringStub stub(masm->isolate());
1257 __ TailCallStub(&stub);
1260 // 3b. Convert symbol in eax to a string.
1261 __ bind(&symbol_descriptive_string);
1263 __ PopReturnAddressTo(ecx);
1265 __ PushReturnAddressFrom(ecx);
1266 __ TailCallRuntime(Runtime::kSymbolDescriptiveString, 1, 1);
1272 void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
1273 // ----------- S t a t e -------------
1274 // -- eax : number of arguments
1275 // -- edi : constructor function
1276 // -- esp[0] : return address
1277 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1278 // -- esp[(argc + 1) * 4] : receiver
1279 // -----------------------------------
1281 // 1. Load the first argument into ebx and get rid of the rest (including the
1284 Label no_arguments, done;
1286 __ j(zero, &no_arguments, Label::kNear);
1287 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1288 __ jmp(&done, Label::kNear);
1289 __ bind(&no_arguments);
1290 __ LoadRoot(ebx, Heap::kempty_stringRootIndex);
1292 __ PopReturnAddressTo(ecx);
1293 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1294 __ PushReturnAddressFrom(ecx);
1297 // 2. Make sure ebx is a string.
1299 Label convert, done_convert;
1300 __ JumpIfSmi(ebx, &convert, Label::kNear);
1301 __ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, edx);
1302 __ j(below, &done_convert);
1305 FrameScope scope(masm, StackFrame::INTERNAL);
1306 ToStringStub stub(masm->isolate());
1313 __ bind(&done_convert);
1316 // 3. Allocate a JSValue wrapper for the string.
1318 // ----------- S t a t e -------------
1319 // -- ebx : the first argument
1320 // -- edi : constructor function
1321 // -----------------------------------
1323 Label allocate, done_allocate;
1324 __ Allocate(JSValue::kSize, eax, ecx, no_reg, &allocate, TAG_OBJECT);
1325 __ bind(&done_allocate);
1327 // Initialize the JSValue in eax.
1328 __ LoadGlobalFunctionInitialMap(edi, ecx);
1329 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1330 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
1331 masm->isolate()->factory()->empty_fixed_array());
1332 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
1333 masm->isolate()->factory()->empty_fixed_array());
1334 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1335 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1338 // Fallback to the runtime to allocate in new space.
1341 FrameScope scope(masm, StackFrame::INTERNAL);
1344 __ Push(Smi::FromInt(JSValue::kSize));
1345 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1349 __ jmp(&done_allocate);
1354 static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1355 Label* stack_overflow) {
1356 // ----------- S t a t e -------------
1357 // -- eax : actual number of arguments
1358 // -- ebx : expected number of arguments
1359 // -- edi : function (passed through to callee)
1360 // -----------------------------------
1361 // Check the stack for overflow. We are not trying to catch
1362 // interruptions (e.g. debug break and preemption) here, so the "real stack
1363 // limit" is checked.
1364 ExternalReference real_stack_limit =
1365 ExternalReference::address_of_real_stack_limit(masm->isolate());
1366 __ mov(edx, Operand::StaticVariable(real_stack_limit));
1367 // Make ecx the space we have left. The stack might already be overflowed
1368 // here which will cause ecx to become negative.
1371 // Make edx the space we need for the array when it is unrolled onto the
1374 __ shl(edx, kPointerSizeLog2);
1375 // Check if the arguments will overflow the stack.
1377 __ j(less_equal, stack_overflow); // Signed comparison.
1381 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1385 // Store the arguments adaptor context sentinel.
1386 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1388 // Push the function on the stack.
1391 // Preserve the number of arguments on the stack. Must preserve eax,
1392 // ebx and ecx because these registers are used when copying the
1393 // arguments and the receiver.
1394 STATIC_ASSERT(kSmiTagSize == 1);
1395 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1400 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1401 // Retrieve the number of arguments from the stack.
1402 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1407 // Remove caller arguments from the stack.
1408 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1410 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1416 void Builtins::Generate_CallFunction(MacroAssembler* masm) {
1417 // ----------- S t a t e -------------
1418 // -- eax : the number of arguments (not including the receiver)
1419 // -- edi : the function to call (checked to be a JSFunction)
1420 // -----------------------------------
1422 Label convert, convert_global_proxy, convert_to_object, done_convert;
1423 __ AssertFunction(edi);
1424 // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal
1425 // slot is "classConstructor".
1426 // Enter the context of the function; ToObject has to run in the function
1427 // context, and we also need to take the global proxy from the function
1428 // context in case of conversion.
1429 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
1430 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
1431 SharedFunctionInfo::kStrictModeByteOffset);
1432 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1433 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1434 // We need to convert the receiver for non-native sloppy mode functions.
1435 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
1436 (1 << SharedFunctionInfo::kNativeBitWithinByte) |
1437 (1 << SharedFunctionInfo::kStrictModeBitWithinByte));
1438 __ j(not_zero, &done_convert);
1440 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
1442 // ----------- S t a t e -------------
1443 // -- eax : the number of arguments (not including the receiver)
1444 // -- ecx : the receiver
1445 // -- edx : the shared function info.
1446 // -- edi : the function to call (checked to be a JSFunction)
1447 // -- esi : the function context.
1448 // -----------------------------------
1450 Label convert_receiver;
1451 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
1452 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
1453 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
1454 __ j(above_equal, &done_convert);
1455 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex, &convert_global_proxy,
1457 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
1459 __ bind(&convert_global_proxy);
1461 // Patch receiver to global proxy.
1462 __ LoadGlobalProxy(ecx);
1464 __ jmp(&convert_receiver);
1465 __ bind(&convert_to_object);
1467 // Convert receiver using ToObject.
1468 // TODO(bmeurer): Inline the allocation here to avoid building the frame
1469 // in the fast case? (fall back to AllocateInNewSpace?)
1470 FrameScope scope(masm, StackFrame::INTERNAL);
1475 ToObjectStub stub(masm->isolate());
1482 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1483 __ bind(&convert_receiver);
1484 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
1486 __ bind(&done_convert);
1488 // ----------- S t a t e -------------
1489 // -- eax : the number of arguments (not including the receiver)
1490 // -- edx : the shared function info.
1491 // -- edi : the function to call (checked to be a JSFunction)
1492 // -- esi : the function context.
1493 // -----------------------------------
1496 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
1498 ParameterCount actual(eax);
1499 ParameterCount expected(ebx);
1500 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), expected,
1501 actual, JUMP_FUNCTION, NullCallWrapper());
1506 void Builtins::Generate_Call(MacroAssembler* masm) {
1507 // ----------- S t a t e -------------
1508 // -- eax : the number of arguments (not including the receiver)
1509 // -- edi : the target to call (can be any Object).
1510 // -----------------------------------
1512 Label non_smi, non_function;
1513 __ JumpIfSmi(edi, &non_function);
1515 __ CmpObjectType(edi, JS_FUNCTION_TYPE, edx);
1516 __ j(equal, masm->isolate()->builtins()->CallFunction(),
1517 RelocInfo::CODE_TARGET);
1518 __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
1519 __ j(not_equal, &non_function);
1521 // 1. Call to function proxy.
1522 // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
1523 __ mov(edi, FieldOperand(edi, JSFunctionProxy::kCallTrapOffset));
1524 __ AssertNotSmi(edi);
1527 // 2. Call to something else, which might have a [[Call]] internal method (if
1528 // not we raise an exception).
1529 __ bind(&non_function);
1530 // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
1531 // be awesome instead; i.e. a trivial improvement would be to call into the
1532 // runtime and just deal with the API function there instead of returning a
1533 // delegate from a runtime call that just jumps back to the runtime once
1534 // called. Or, bonus points, call directly into the C API function here, as
1535 // we do in some Crankshaft fast cases.
1536 // Overwrite the original receiver with the (original) target.
1537 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
1539 // Determine the delegate for the target (if any).
1540 FrameScope scope(masm, StackFrame::INTERNAL);
1544 __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
1549 // The delegate is always a regular function.
1550 __ AssertFunction(edi);
1551 __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
1556 void Builtins::Generate_PushArgsAndCall(MacroAssembler* masm) {
1557 // ----------- S t a t e -------------
1558 // -- eax : the number of arguments (not including the receiver)
1559 // -- ebx : the address of the first argument to be pushed. Subsequent
1560 // arguments should be consecutive above this, in the same order as
1561 // they are to be pushed onto the stack.
1562 // -- edi : the target to call (can be any Object).
1564 // Pop return address to allow tail-call after pushing arguments.
1567 // Find the address of the last argument.
1569 __ add(ecx, Immediate(1)); // Add one for receiver.
1570 __ shl(ecx, kPointerSizeLog2);
1574 // Push the arguments.
1575 Label loop_header, loop_check;
1576 __ jmp(&loop_check);
1577 __ bind(&loop_header);
1578 __ Push(Operand(ebx, 0));
1579 __ sub(ebx, Immediate(kPointerSize));
1580 __ bind(&loop_check);
1582 __ j(greater, &loop_header, Label::kNear);
1585 __ Push(edx); // Re-push return address.
1586 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1590 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1591 // ----------- S t a t e -------------
1592 // -- eax : actual number of arguments
1593 // -- ebx : expected number of arguments
1594 // -- edi : function (passed through to callee)
1595 // -----------------------------------
1597 Label invoke, dont_adapt_arguments;
1598 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
1600 Label stack_overflow;
1601 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
1603 Label enough, too_few;
1604 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
1606 __ j(less, &too_few);
1607 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1608 __ j(equal, &dont_adapt_arguments);
1610 { // Enough parameters: Actual >= expected.
1612 EnterArgumentsAdaptorFrame(masm);
1614 // Copy receiver and all expected arguments.
1615 const int offset = StandardFrameConstants::kCallerSPOffset;
1616 __ lea(edi, Operand(ebp, eax, times_4, offset));
1617 __ mov(eax, -1); // account for receiver
1622 __ push(Operand(edi, 0));
1623 __ sub(edi, Immediate(kPointerSize));
1626 // eax now contains the expected number of arguments.
1630 { // Too few parameters: Actual < expected.
1633 // If the function is strong we need to throw an error.
1634 Label no_strong_error;
1635 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1636 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrongModeByteOffset),
1637 1 << SharedFunctionInfo::kStrongModeBitWithinByte);
1638 __ j(equal, &no_strong_error, Label::kNear);
1640 // What we really care about is the required number of arguments.
1641 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kLengthOffset));
1644 __ j(greater_equal, &no_strong_error, Label::kNear);
1647 FrameScope frame(masm, StackFrame::MANUAL);
1648 EnterArgumentsAdaptorFrame(masm);
1649 __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments, 0);
1652 __ bind(&no_strong_error);
1653 EnterArgumentsAdaptorFrame(masm);
1655 // Remember expected arguments in ecx.
1658 // Copy receiver and all actual arguments.
1659 const int offset = StandardFrameConstants::kCallerSPOffset;
1660 __ lea(edi, Operand(ebp, eax, times_4, offset));
1661 // ebx = expected - actual.
1663 // eax = -actual - 1
1665 __ sub(eax, Immediate(1));
1670 __ push(Operand(edi, 0));
1671 __ sub(edi, Immediate(kPointerSize));
1673 __ j(not_zero, ©);
1675 // Fill remaining expected arguments with undefined values.
1679 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
1683 // Restore expected arguments.
1687 // Call the entry point.
1689 // Restore function pointer.
1690 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1691 // eax : expected number of arguments
1692 // edi : function (passed through to callee)
1695 // Store offset of return address for deoptimizer.
1696 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1698 // Leave frame and return.
1699 LeaveArgumentsAdaptorFrame(masm);
1702 // -------------------------------------------
1703 // Dont adapt arguments.
1704 // -------------------------------------------
1705 __ bind(&dont_adapt_arguments);
1708 __ bind(&stack_overflow);
1710 FrameScope frame(masm, StackFrame::MANUAL);
1711 EnterArgumentsAdaptorFrame(masm);
1712 __ CallRuntime(Runtime::kThrowStackOverflow, 0);
1718 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1719 // Lookup the function in the JavaScript frame.
1720 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1722 FrameScope scope(masm, StackFrame::INTERNAL);
1723 // Pass function as argument.
1725 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1729 // If the code object is null, just return to the unoptimized code.
1730 __ cmp(eax, Immediate(0));
1731 __ j(not_equal, &skip, Label::kNear);
1736 // Load deoptimization data from the code object.
1737 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1739 // Load the OSR entrypoint offset from the deoptimization data.
1740 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
1741 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
1744 // Compute the target address = code_obj + header_size + osr_offset
1745 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
1747 // Overwrite the return address on the stack.
1748 __ mov(Operand(esp, 0), eax);
1750 // And "return" to the OSR entry point of the function.
1755 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1756 // We check the stack limit as indicator that recompilation might be done.
1758 ExternalReference stack_limit =
1759 ExternalReference::address_of_stack_limit(masm->isolate());
1760 __ cmp(esp, Operand::StaticVariable(stack_limit));
1761 __ j(above_equal, &ok, Label::kNear);
1763 FrameScope scope(masm, StackFrame::INTERNAL);
1764 __ CallRuntime(Runtime::kStackGuard, 0);
1766 __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
1767 RelocInfo::CODE_TARGET);
1774 } // namespace internal
1777 #endif // V8_TARGET_ARCH_IA32