OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_X64 | 5 #if V8_TARGET_ARCH_X64 |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/codegen.h" | 8 #include "src/codegen.h" |
9 #include "src/deoptimizer.h" | 9 #include "src/deoptimizer.h" |
10 #include "src/full-codegen/full-codegen.h" | 10 #include "src/full-codegen/full-codegen.h" |
(...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
713 __ bind(&switch_to_different_code_kind); | 713 __ bind(&switch_to_different_code_kind); |
714 __ leave(); // Leave the frame so we can tail call. | 714 __ leave(); // Leave the frame so we can tail call. |
715 __ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 715 __ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
716 __ movp(rcx, FieldOperand(rcx, SharedFunctionInfo::kCodeOffset)); | 716 __ movp(rcx, FieldOperand(rcx, SharedFunctionInfo::kCodeOffset)); |
717 __ leap(rcx, FieldOperand(rcx, Code::kHeaderSize)); | 717 __ leap(rcx, FieldOperand(rcx, Code::kHeaderSize)); |
718 __ movp(FieldOperand(rdi, JSFunction::kCodeEntryOffset), rcx); | 718 __ movp(FieldOperand(rdi, JSFunction::kCodeEntryOffset), rcx); |
719 __ RecordWriteCodeEntryField(rdi, rcx, r15); | 719 __ RecordWriteCodeEntryField(rdi, rcx, r15); |
720 __ jmp(rcx); | 720 __ jmp(rcx); |
721 } | 721 } |
722 | 722 |
723 static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, | 723 static void Generate_StackOverflowCheck( |
724 Register scratch1, Register scratch2, | 724 MacroAssembler* masm, Register num_args, Register scratch, |
725 Label* stack_overflow) { | 725 Label* stack_overflow, |
| 726 Label::Distance stack_overflow_distance = Label::kFar) { |
726 // Check the stack for overflow. We are not trying to catch | 727 // Check the stack for overflow. We are not trying to catch |
727 // interruptions (e.g. debug break and preemption) here, so the "real stack | 728 // interruptions (e.g. debug break and preemption) here, so the "real stack |
728 // limit" is checked. | 729 // limit" is checked. |
729 __ LoadRoot(scratch1, Heap::kRealStackLimitRootIndex); | 730 __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex); |
730 __ movp(scratch2, rsp); | 731 __ movp(scratch, rsp); |
731 // Make scratch2 the space we have left. The stack might already be overflowed | 732 // Make scratch the space we have left. The stack might already be overflowed |
732 // here which will cause scratch2 to become negative. | 733 // here which will cause scratch to become negative. |
733 __ subp(scratch2, scratch1); | 734 __ subp(scratch, kScratchRegister); |
734 // Make scratch1 the space we need for the array when it is unrolled onto the | 735 __ sarp(scratch, Immediate(kPointerSizeLog2)); |
735 // stack. | |
736 __ movp(scratch1, num_args); | |
737 __ shlp(scratch1, Immediate(kPointerSizeLog2)); | |
738 // Check if the arguments will overflow the stack. | 736 // Check if the arguments will overflow the stack. |
739 __ cmpp(scratch2, scratch1); | 737 __ cmpp(scratch, num_args); |
740 __ j(less_equal, stack_overflow); // Signed comparison. | 738 // Signed comparison. |
| 739 __ j(less_equal, stack_overflow, stack_overflow_distance); |
741 } | 740 } |
742 | 741 |
743 static void Generate_InterpreterPushArgs(MacroAssembler* masm, | 742 static void Generate_InterpreterPushArgs(MacroAssembler* masm, |
744 Register num_args, | 743 Register num_args, |
745 Register start_address, | 744 Register start_address, |
746 Register scratch) { | 745 Register scratch) { |
747 // Find the address of the last argument. | 746 // Find the address of the last argument. |
748 __ Move(scratch, num_args); | 747 __ Move(scratch, num_args); |
749 __ shlp(scratch, Immediate(kPointerSizeLog2)); | 748 __ shlp(scratch, Immediate(kPointerSizeLog2)); |
750 __ negp(scratch); | 749 __ negp(scratch); |
(...skipping 21 matching lines...) Expand all Loading... |
772 // they are to be pushed onto the stack. | 771 // they are to be pushed onto the stack. |
773 // -- rdi : the target to call (can be any Object). | 772 // -- rdi : the target to call (can be any Object). |
774 // ----------------------------------- | 773 // ----------------------------------- |
775 Label stack_overflow; | 774 Label stack_overflow; |
776 | 775 |
777 // Number of values to be pushed. | 776 // Number of values to be pushed. |
778 __ Move(rcx, rax); | 777 __ Move(rcx, rax); |
779 __ addp(rcx, Immediate(1)); // Add one for receiver. | 778 __ addp(rcx, Immediate(1)); // Add one for receiver. |
780 | 779 |
781 // Add a stack check before pushing arguments. | 780 // Add a stack check before pushing arguments. |
782 Generate_StackOverflowCheck(masm, rcx, rdx, r8, &stack_overflow); | 781 Generate_StackOverflowCheck(masm, rcx, rdx, &stack_overflow); |
783 | 782 |
784 // Pop return address to allow tail-call after pushing arguments. | 783 // Pop return address to allow tail-call after pushing arguments. |
785 __ PopReturnAddressTo(kScratchRegister); | 784 __ PopReturnAddressTo(kScratchRegister); |
786 | 785 |
787 // rbx and rdx will be modified. | 786 // rbx and rdx will be modified. |
788 Generate_InterpreterPushArgs(masm, rcx, rbx, rdx); | 787 Generate_InterpreterPushArgs(masm, rcx, rbx, rdx); |
789 | 788 |
790 // Call the target. | 789 // Call the target. |
791 __ PushReturnAddressFrom(kScratchRegister); // Re-push return address. | 790 __ PushReturnAddressFrom(kScratchRegister); // Re-push return address. |
792 | 791 |
(...skipping 28 matching lines...) Expand all Loading... |
821 // the JSFunction on which new was invoked initially) | 820 // the JSFunction on which new was invoked initially) |
822 // -- rdi : the constructor to call (can be any Object) | 821 // -- rdi : the constructor to call (can be any Object) |
823 // -- rbx : the allocation site feedback if available, undefined otherwise | 822 // -- rbx : the allocation site feedback if available, undefined otherwise |
824 // -- rcx : the address of the first argument to be pushed. Subsequent | 823 // -- rcx : the address of the first argument to be pushed. Subsequent |
825 // arguments should be consecutive above this, in the same order as | 824 // arguments should be consecutive above this, in the same order as |
826 // they are to be pushed onto the stack. | 825 // they are to be pushed onto the stack. |
827 // ----------------------------------- | 826 // ----------------------------------- |
828 Label stack_overflow; | 827 Label stack_overflow; |
829 | 828 |
830 // Add a stack check before pushing arguments. | 829 // Add a stack check before pushing arguments. |
831 Generate_StackOverflowCheck(masm, rax, r8, r9, &stack_overflow); | 830 Generate_StackOverflowCheck(masm, rax, r8, &stack_overflow); |
832 | 831 |
833 // Pop return address to allow tail-call after pushing arguments. | 832 // Pop return address to allow tail-call after pushing arguments. |
834 __ PopReturnAddressTo(kScratchRegister); | 833 __ PopReturnAddressTo(kScratchRegister); |
835 | 834 |
836 // Push slot for the receiver to be constructed. | 835 // Push slot for the receiver to be constructed. |
837 __ Push(Immediate(0)); | 836 __ Push(Immediate(0)); |
838 | 837 |
839 // rcx and r8 will be modified. | 838 // rcx and r8 will be modified. |
840 Generate_InterpreterPushArgs(masm, rax, rcx, r8); | 839 Generate_InterpreterPushArgs(masm, rax, rcx, r8); |
841 | 840 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
883 // arguments should be consecutive above this, in the same order as | 882 // arguments should be consecutive above this, in the same order as |
884 // they are to be pushed onto the stack. | 883 // they are to be pushed onto the stack. |
885 // ----------------------------------- | 884 // ----------------------------------- |
886 Label stack_overflow; | 885 Label stack_overflow; |
887 | 886 |
888 // Number of values to be pushed. | 887 // Number of values to be pushed. |
889 __ Move(r8, rax); | 888 __ Move(r8, rax); |
890 __ addp(r8, Immediate(1)); // Add one for receiver. | 889 __ addp(r8, Immediate(1)); // Add one for receiver. |
891 | 890 |
892 // Add a stack check before pushing arguments. | 891 // Add a stack check before pushing arguments. |
893 Generate_StackOverflowCheck(masm, r8, rdi, r9, &stack_overflow); | 892 Generate_StackOverflowCheck(masm, r8, rdi, &stack_overflow); |
894 | 893 |
895 // Pop return address to allow tail-call after pushing arguments. | 894 // Pop return address to allow tail-call after pushing arguments. |
896 __ PopReturnAddressTo(kScratchRegister); | 895 __ PopReturnAddressTo(kScratchRegister); |
897 | 896 |
898 // rcx and rdi will be modified. | 897 // rcx and rdi will be modified. |
899 Generate_InterpreterPushArgs(masm, r8, rcx, rdi); | 898 Generate_InterpreterPushArgs(masm, r8, rcx, rdi); |
900 | 899 |
901 // Push return address in preparation for the tail-call. | 900 // Push return address in preparation for the tail-call. |
902 __ PushReturnAddressFrom(kScratchRegister); | 901 __ PushReturnAddressFrom(kScratchRegister); |
903 | 902 |
(...skipping 1236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2140 Label enough, too_few; | 2139 Label enough, too_few; |
2141 __ cmpp(rax, rbx); | 2140 __ cmpp(rax, rbx); |
2142 __ j(less, &too_few); | 2141 __ j(less, &too_few); |
2143 __ cmpp(rbx, Immediate(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); | 2142 __ cmpp(rbx, Immediate(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); |
2144 __ j(equal, &dont_adapt_arguments); | 2143 __ j(equal, &dont_adapt_arguments); |
2145 | 2144 |
2146 { // Enough parameters: Actual >= expected. | 2145 { // Enough parameters: Actual >= expected. |
2147 __ bind(&enough); | 2146 __ bind(&enough); |
2148 EnterArgumentsAdaptorFrame(masm); | 2147 EnterArgumentsAdaptorFrame(masm); |
2149 // The registers rcx and r8 will be modified. The register rbx is only read. | 2148 // The registers rcx and r8 will be modified. The register rbx is only read. |
2150 Generate_StackOverflowCheck(masm, rbx, rcx, r8, &stack_overflow); | 2149 Generate_StackOverflowCheck(masm, rbx, rcx, &stack_overflow); |
2151 | 2150 |
2152 // Copy receiver and all expected arguments. | 2151 // Copy receiver and all expected arguments. |
2153 const int offset = StandardFrameConstants::kCallerSPOffset; | 2152 const int offset = StandardFrameConstants::kCallerSPOffset; |
2154 __ leap(rax, Operand(rbp, rax, times_pointer_size, offset)); | 2153 __ leap(rax, Operand(rbp, rax, times_pointer_size, offset)); |
2155 __ Set(r8, -1); // account for receiver | 2154 __ Set(r8, -1); // account for receiver |
2156 | 2155 |
2157 Label copy; | 2156 Label copy; |
2158 __ bind(©); | 2157 __ bind(©); |
2159 __ incp(r8); | 2158 __ incp(r8); |
2160 __ Push(Operand(rax, 0)); | 2159 __ Push(Operand(rax, 0)); |
2161 __ subp(rax, Immediate(kPointerSize)); | 2160 __ subp(rax, Immediate(kPointerSize)); |
2162 __ cmpp(r8, rbx); | 2161 __ cmpp(r8, rbx); |
2163 __ j(less, ©); | 2162 __ j(less, ©); |
2164 __ jmp(&invoke); | 2163 __ jmp(&invoke); |
2165 } | 2164 } |
2166 | 2165 |
2167 { // Too few parameters: Actual < expected. | 2166 { // Too few parameters: Actual < expected. |
2168 __ bind(&too_few); | 2167 __ bind(&too_few); |
2169 | 2168 |
2170 EnterArgumentsAdaptorFrame(masm); | 2169 EnterArgumentsAdaptorFrame(masm); |
2171 // The registers rcx and r8 will be modified. The register rbx is only read. | 2170 // The registers rcx and r8 will be modified. The register rbx is only read. |
2172 Generate_StackOverflowCheck(masm, rbx, rcx, r8, &stack_overflow); | 2171 Generate_StackOverflowCheck(masm, rbx, rcx, &stack_overflow); |
2173 | 2172 |
2174 // Copy receiver and all actual arguments. | 2173 // Copy receiver and all actual arguments. |
2175 const int offset = StandardFrameConstants::kCallerSPOffset; | 2174 const int offset = StandardFrameConstants::kCallerSPOffset; |
2176 __ leap(rdi, Operand(rbp, rax, times_pointer_size, offset)); | 2175 __ leap(rdi, Operand(rbp, rax, times_pointer_size, offset)); |
2177 __ Set(r8, -1); // account for receiver | 2176 __ Set(r8, -1); // account for receiver |
2178 | 2177 |
2179 Label copy; | 2178 Label copy; |
2180 __ bind(©); | 2179 __ bind(©); |
2181 __ incp(r8); | 2180 __ incp(r8); |
2182 __ Push(Operand(rdi, 0)); | 2181 __ Push(Operand(rdi, 0)); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2369 } | 2368 } |
2370 | 2369 |
2371 // Dispatch to Call or Construct depending on whether new.target is undefined. | 2370 // Dispatch to Call or Construct depending on whether new.target is undefined. |
2372 { | 2371 { |
2373 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 2372 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
2374 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); | 2373 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
2375 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 2374 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
2376 } | 2375 } |
2377 } | 2376 } |
2378 | 2377 |
| 2378 // static |
| 2379 void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm, |
| 2380 Handle<Code> code) { |
| 2381 // ----------- S t a t e ------------- |
| 2382 // -- rdi : the target to call (can be any Object) |
| 2383 // -- rcx : start index (to support rest parameters) |
| 2384 // -- rsp[0] : return address. |
| 2385 // -- rsp[8] : thisArgument |
| 2386 // ----------------------------------- |
| 2387 |
| 2388 // Check if we have an arguments adaptor frame below the function frame. |
| 2389 Label arguments_adaptor, arguments_done; |
| 2390 __ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2391 __ Cmp(Operand(rbx, CommonFrameConstants::kContextOrFrameTypeOffset), |
| 2392 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2393 __ j(equal, &arguments_adaptor, Label::kNear); |
| 2394 { |
| 2395 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 2396 __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); |
| 2397 __ LoadSharedFunctionInfoSpecialField( |
| 2398 rax, rax, SharedFunctionInfo::kFormalParameterCountOffset); |
| 2399 __ movp(rbx, rbp); |
| 2400 } |
| 2401 __ jmp(&arguments_done, Label::kNear); |
| 2402 __ bind(&arguments_adaptor); |
| 2403 { |
| 2404 __ SmiToInteger32( |
| 2405 rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2406 } |
| 2407 __ bind(&arguments_done); |
| 2408 |
| 2409 Label stack_empty, stack_done, stack_overflow; |
| 2410 __ subl(rax, rcx); |
| 2411 __ j(less_equal, &stack_empty); |
| 2412 { |
| 2413 // Check for stack overflow. |
| 2414 Generate_StackOverflowCheck(masm, rax, rcx, &stack_overflow, Label::kNear); |
| 2415 |
| 2416 // Forward the arguments from the caller frame. |
| 2417 { |
| 2418 Label loop; |
| 2419 __ movl(rcx, rax); |
| 2420 __ Pop(r8); |
| 2421 __ bind(&loop); |
| 2422 { |
| 2423 StackArgumentsAccessor args(rbx, rcx, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 2424 __ Push(args.GetArgumentOperand(0)); |
| 2425 __ decl(rcx); |
| 2426 __ j(not_zero, &loop); |
| 2427 } |
| 2428 __ Push(r8); |
| 2429 } |
| 2430 } |
| 2431 __ jmp(&stack_done, Label::kNear); |
| 2432 __ bind(&stack_overflow); |
| 2433 __ TailCallRuntime(Runtime::kThrowStackOverflow); |
| 2434 __ bind(&stack_empty); |
| 2435 { |
| 2436 // We just pass the receiver, which is already on the stack. |
| 2437 __ Set(rax, 0); |
| 2438 } |
| 2439 __ bind(&stack_done); |
| 2440 |
| 2441 __ Jump(code, RelocInfo::CODE_TARGET); |
| 2442 } |
| 2443 |
2379 namespace { | 2444 namespace { |
2380 | 2445 |
2381 // Drops top JavaScript frame and an arguments adaptor frame below it (if | 2446 // Drops top JavaScript frame and an arguments adaptor frame below it (if |
2382 // present) preserving all the arguments prepared for current call. | 2447 // present) preserving all the arguments prepared for current call. |
2383 // Does nothing if debugger is currently active. | 2448 // Does nothing if debugger is currently active. |
2384 // ES6 14.6.3. PrepareForTailCall | 2449 // ES6 14.6.3. PrepareForTailCall |
2385 // | 2450 // |
2386 // Stack structure for the function g() tail calling f(): | 2451 // Stack structure for the function g() tail calling f(): |
2387 // | 2452 // |
2388 // ------- Caller frame: ------- | 2453 // ------- Caller frame: ------- |
(...skipping 811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3200 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { | 3265 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { |
3201 Generate_OnStackReplacementHelper(masm, true); | 3266 Generate_OnStackReplacementHelper(masm, true); |
3202 } | 3267 } |
3203 | 3268 |
3204 #undef __ | 3269 #undef __ |
3205 | 3270 |
3206 } // namespace internal | 3271 } // namespace internal |
3207 } // namespace v8 | 3272 } // namespace v8 |
3208 | 3273 |
3209 #endif // V8_TARGET_ARCH_X64 | 3274 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |