| 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 |