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 681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 __ Move( | 692 __ Move( |
693 kInterpreterDispatchTableRegister, | 693 kInterpreterDispatchTableRegister, |
694 ExternalReference::interpreter_dispatch_table_address(masm->isolate())); | 694 ExternalReference::interpreter_dispatch_table_address(masm->isolate())); |
695 | 695 |
696 // Dispatch to the first bytecode handler for the function. | 696 // Dispatch to the first bytecode handler for the function. |
697 __ movzxbp(rbx, Operand(kInterpreterBytecodeArrayRegister, | 697 __ movzxbp(rbx, Operand(kInterpreterBytecodeArrayRegister, |
698 kInterpreterBytecodeOffsetRegister, times_1, 0)); | 698 kInterpreterBytecodeOffsetRegister, times_1, 0)); |
699 __ movp(rbx, Operand(kInterpreterDispatchTableRegister, rbx, | 699 __ movp(rbx, Operand(kInterpreterDispatchTableRegister, rbx, |
700 times_pointer_size, 0)); | 700 times_pointer_size, 0)); |
701 __ call(rbx); | 701 __ call(rbx); |
702 masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset()); | |
703 | 702 |
704 // The return value is in rax. | 703 // Even though the first bytecode handler was called, we will never return. |
705 | 704 __ Abort(kUnexpectedReturnFromBytecodeHandler); |
706 // Get the arguments + reciever count. | |
707 __ movp(rbx, Operand(rbp, InterpreterFrameConstants::kBytecodeArrayFromFp)); | |
708 __ movl(rbx, FieldOperand(rbx, BytecodeArray::kParameterSizeOffset)); | |
709 | |
710 // Leave the frame (also dropping the register file). | |
711 __ leave(); | |
712 | |
713 // Drop receiver + arguments and return. | |
714 __ PopReturnAddressTo(rcx); | |
715 __ addp(rsp, rbx); | |
716 __ PushReturnAddressFrom(rcx); | |
717 __ ret(0); | |
718 | 705 |
719 // Load debug copy of the bytecode array. | 706 // Load debug copy of the bytecode array. |
720 __ bind(&load_debug_bytecode_array); | 707 __ bind(&load_debug_bytecode_array); |
721 Register debug_info = kInterpreterBytecodeArrayRegister; | 708 Register debug_info = kInterpreterBytecodeArrayRegister; |
722 __ movp(debug_info, FieldOperand(rax, SharedFunctionInfo::kDebugInfoOffset)); | 709 __ movp(debug_info, FieldOperand(rax, SharedFunctionInfo::kDebugInfoOffset)); |
723 __ movp(kInterpreterBytecodeArrayRegister, | 710 __ movp(kInterpreterBytecodeArrayRegister, |
724 FieldOperand(debug_info, DebugInfo::kAbstractCodeIndex)); | 711 FieldOperand(debug_info, DebugInfo::kAbstractCodeIndex)); |
725 __ jmp(&bytecode_array_loaded); | 712 __ jmp(&bytecode_array_loaded); |
726 | 713 |
727 // If the bytecode array is no longer present, then the underlying function | 714 // If the bytecode array is no longer present, then the underlying function |
728 // has been switched to a different kind of code and we heal the closure by | 715 // has been switched to a different kind of code and we heal the closure by |
729 // switching the code entry field over to the new code object as well. | 716 // switching the code entry field over to the new code object as well. |
730 __ bind(&bytecode_array_not_present); | 717 __ bind(&bytecode_array_not_present); |
731 __ leave(); // Leave the frame so we can tail call. | 718 __ leave(); // Leave the frame so we can tail call. |
732 __ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 719 __ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
733 __ movp(rcx, FieldOperand(rcx, SharedFunctionInfo::kCodeOffset)); | 720 __ movp(rcx, FieldOperand(rcx, SharedFunctionInfo::kCodeOffset)); |
734 __ leap(rcx, FieldOperand(rcx, Code::kHeaderSize)); | 721 __ leap(rcx, FieldOperand(rcx, Code::kHeaderSize)); |
735 __ movp(FieldOperand(rdi, JSFunction::kCodeEntryOffset), rcx); | 722 __ movp(FieldOperand(rdi, JSFunction::kCodeEntryOffset), rcx); |
736 __ RecordWriteCodeEntryField(rdi, rcx, r15); | 723 __ RecordWriteCodeEntryField(rdi, rcx, r15); |
737 __ jmp(rcx); | 724 __ jmp(rcx); |
738 } | 725 } |
739 | 726 |
| 727 |
| 728 void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { |
| 729 // The return value is in accumulator, which is already in rax. |
| 730 |
| 731 // Leave the frame (also dropping the register file). |
| 732 __ leave(); |
| 733 |
| 734 // Drop receiver + arguments and return. |
| 735 __ movl(rbx, FieldOperand(kInterpreterBytecodeArrayRegister, |
| 736 BytecodeArray::kParameterSizeOffset)); |
| 737 __ PopReturnAddressTo(rcx); |
| 738 __ addp(rsp, rbx); |
| 739 __ PushReturnAddressFrom(rcx); |
| 740 __ ret(0); |
| 741 } |
| 742 |
| 743 |
740 static void Generate_InterpreterPushArgs(MacroAssembler* masm, | 744 static void Generate_InterpreterPushArgs(MacroAssembler* masm, |
741 bool push_receiver) { | 745 bool push_receiver) { |
742 // ----------- S t a t e ------------- | 746 // ----------- S t a t e ------------- |
743 // -- rax : the number of arguments (not including the receiver) | 747 // -- rax : the number of arguments (not including the receiver) |
744 // -- rbx : the address of the first argument to be pushed. Subsequent | 748 // -- rbx : the address of the first argument to be pushed. Subsequent |
745 // arguments should be consecutive above this, in the same order as | 749 // arguments should be consecutive above this, in the same order as |
746 // they are to be pushed onto the stack. | 750 // they are to be pushed onto the stack. |
747 // ----------------------------------- | 751 // ----------------------------------- |
748 | 752 |
749 // Find the address of the last argument. | 753 // Find the address of the last argument. |
(...skipping 10 matching lines...) Expand all Loading... |
760 Label loop_header, loop_check; | 764 Label loop_header, loop_check; |
761 __ j(always, &loop_check); | 765 __ j(always, &loop_check); |
762 __ bind(&loop_header); | 766 __ bind(&loop_header); |
763 __ Push(Operand(rbx, 0)); | 767 __ Push(Operand(rbx, 0)); |
764 __ subp(rbx, Immediate(kPointerSize)); | 768 __ subp(rbx, Immediate(kPointerSize)); |
765 __ bind(&loop_check); | 769 __ bind(&loop_check); |
766 __ cmpp(rbx, rcx); | 770 __ cmpp(rbx, rcx); |
767 __ j(greater, &loop_header, Label::kNear); | 771 __ j(greater, &loop_header, Label::kNear); |
768 } | 772 } |
769 | 773 |
| 774 |
770 // static | 775 // static |
771 void Builtins::Generate_InterpreterPushArgsAndCallImpl( | 776 void Builtins::Generate_InterpreterPushArgsAndCallImpl( |
772 MacroAssembler* masm, TailCallMode tail_call_mode) { | 777 MacroAssembler* masm, TailCallMode tail_call_mode) { |
773 // ----------- S t a t e ------------- | 778 // ----------- S t a t e ------------- |
774 // -- rax : the number of arguments (not including the receiver) | 779 // -- rax : the number of arguments (not including the receiver) |
775 // -- rbx : the address of the first argument to be pushed. Subsequent | 780 // -- rbx : the address of the first argument to be pushed. Subsequent |
776 // arguments should be consecutive above this, in the same order as | 781 // arguments should be consecutive above this, in the same order as |
777 // they are to be pushed onto the stack. | 782 // they are to be pushed onto the stack. |
778 // -- rdi : the target to call (can be any Object). | 783 // -- rdi : the target to call (can be any Object). |
779 // ----------------------------------- | 784 // ----------------------------------- |
780 | 785 |
781 // Pop return address to allow tail-call after pushing arguments. | 786 // Pop return address to allow tail-call after pushing arguments. |
782 __ PopReturnAddressTo(kScratchRegister); | 787 __ PopReturnAddressTo(kScratchRegister); |
783 | 788 |
784 Generate_InterpreterPushArgs(masm, true); | 789 Generate_InterpreterPushArgs(masm, true); |
785 | 790 |
786 // Call the target. | 791 // Call the target. |
787 __ PushReturnAddressFrom(kScratchRegister); // Re-push return address. | 792 __ PushReturnAddressFrom(kScratchRegister); // Re-push return address. |
788 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, | 793 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, |
789 tail_call_mode), | 794 tail_call_mode), |
790 RelocInfo::CODE_TARGET); | 795 RelocInfo::CODE_TARGET); |
791 } | 796 } |
792 | 797 |
| 798 |
793 // static | 799 // static |
794 void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { | 800 void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { |
795 // ----------- S t a t e ------------- | 801 // ----------- S t a t e ------------- |
796 // -- rax : the number of arguments (not including the receiver) | 802 // -- rax : the number of arguments (not including the receiver) |
797 // -- rdx : the new target (either the same as the constructor or | 803 // -- rdx : the new target (either the same as the constructor or |
798 // the JSFunction on which new was invoked initially) | 804 // the JSFunction on which new was invoked initially) |
799 // -- rdi : the constructor to call (can be any Object) | 805 // -- rdi : the constructor to call (can be any Object) |
800 // -- rbx : the address of the first argument to be pushed. Subsequent | 806 // -- rbx : the address of the first argument to be pushed. Subsequent |
801 // arguments should be consecutive above this, in the same order as | 807 // arguments should be consecutive above this, in the same order as |
802 // they are to be pushed onto the stack. | 808 // they are to be pushed onto the stack. |
803 // ----------------------------------- | 809 // ----------------------------------- |
804 | 810 |
805 // Pop return address to allow tail-call after pushing arguments. | 811 // Pop return address to allow tail-call after pushing arguments. |
806 __ PopReturnAddressTo(kScratchRegister); | 812 __ PopReturnAddressTo(kScratchRegister); |
807 | 813 |
808 // Push slot for the receiver to be constructed. | 814 // Push slot for the receiver to be constructed. |
809 __ Push(Immediate(0)); | 815 __ Push(Immediate(0)); |
810 | 816 |
811 Generate_InterpreterPushArgs(masm, false); | 817 Generate_InterpreterPushArgs(masm, false); |
812 | 818 |
813 // Push return address in preparation for the tail-call. | 819 // Push return address in preparation for the tail-call. |
814 __ PushReturnAddressFrom(kScratchRegister); | 820 __ PushReturnAddressFrom(kScratchRegister); |
815 | 821 |
816 // Call the constructor (rax, rdx, rdi passed on). | 822 // Call the constructor (rax, rdx, rdi passed on). |
817 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 823 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
818 } | 824 } |
819 | 825 |
820 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { | |
821 // Set the return address to the correct point in the interpreter entry | |
822 // trampoline. | |
823 Smi* interpreter_entry_return_pc_offset( | |
824 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); | |
825 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); | |
826 __ Move(rbx, masm->isolate()->builtins()->InterpreterEntryTrampoline()); | |
827 __ addp(rbx, Immediate(interpreter_entry_return_pc_offset->value() + | |
828 Code::kHeaderSize - kHeapObjectTag)); | |
829 __ Push(rbx); | |
830 | 826 |
| 827 static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) { |
831 // Initialize dispatch table register. | 828 // Initialize dispatch table register. |
832 __ Move( | 829 __ Move( |
833 kInterpreterDispatchTableRegister, | 830 kInterpreterDispatchTableRegister, |
834 ExternalReference::interpreter_dispatch_table_address(masm->isolate())); | 831 ExternalReference::interpreter_dispatch_table_address(masm->isolate())); |
835 | 832 |
836 // Get the bytecode array pointer from the frame. | 833 // Get the bytecode array pointer from the frame. |
837 __ movp(kInterpreterBytecodeArrayRegister, | 834 __ movp(kInterpreterBytecodeArrayRegister, |
838 Operand(rbp, InterpreterFrameConstants::kBytecodeArrayFromFp)); | 835 Operand(rbp, InterpreterFrameConstants::kBytecodeArrayFromFp)); |
839 | 836 |
840 if (FLAG_debug_code) { | 837 if (FLAG_debug_code) { |
(...skipping 11 matching lines...) Expand all Loading... |
852 kInterpreterBytecodeOffsetRegister); | 849 kInterpreterBytecodeOffsetRegister); |
853 | 850 |
854 // Dispatch to the target bytecode. | 851 // Dispatch to the target bytecode. |
855 __ movzxbp(rbx, Operand(kInterpreterBytecodeArrayRegister, | 852 __ movzxbp(rbx, Operand(kInterpreterBytecodeArrayRegister, |
856 kInterpreterBytecodeOffsetRegister, times_1, 0)); | 853 kInterpreterBytecodeOffsetRegister, times_1, 0)); |
857 __ movp(rbx, Operand(kInterpreterDispatchTableRegister, rbx, | 854 __ movp(rbx, Operand(kInterpreterDispatchTableRegister, rbx, |
858 times_pointer_size, 0)); | 855 times_pointer_size, 0)); |
859 __ jmp(rbx); | 856 __ jmp(rbx); |
860 } | 857 } |
861 | 858 |
| 859 |
| 860 static void Generate_InterpreterNotifyDeoptimizedHelper( |
| 861 MacroAssembler* masm, Deoptimizer::BailoutType type) { |
| 862 // Enter an internal frame. |
| 863 { |
| 864 FrameScope scope(masm, StackFrame::INTERNAL); |
| 865 |
| 866 // Pass the deoptimization type to the runtime system. |
| 867 __ Push(Smi::FromInt(static_cast<int>(type))); |
| 868 __ CallRuntime(Runtime::kNotifyDeoptimized); |
| 869 // Tear down internal frame. |
| 870 } |
| 871 |
| 872 // Drop state (we don't use these for interpreter deopts) and and pop the |
| 873 // accumulator value into the accumulator register and push PC at top |
| 874 // of stack (to simulate initial call to bytecode handler in interpreter entry |
| 875 // trampoline). |
| 876 __ Pop(rbx); |
| 877 __ Drop(1); |
| 878 __ Pop(kInterpreterAccumulatorRegister); |
| 879 __ Push(rbx); |
| 880 |
| 881 // Enter the bytecode dispatch. |
| 882 Generate_EnterBytecodeDispatch(masm); |
| 883 } |
| 884 |
| 885 |
| 886 void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) { |
| 887 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER); |
| 888 } |
| 889 |
| 890 |
| 891 void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) { |
| 892 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT); |
| 893 } |
| 894 |
| 895 |
| 896 void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) { |
| 897 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY); |
| 898 } |
| 899 |
| 900 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { |
| 901 // Set the address of the interpreter entry trampoline as a return address. |
| 902 // This simulates the initial call to bytecode handlers in interpreter entry |
| 903 // trampoline. The return will never actually be taken, but our stack walker |
| 904 // uses this address to determine whether a frame is interpreted. |
| 905 __ Push(masm->isolate()->builtins()->InterpreterEntryTrampoline()); |
| 906 |
| 907 Generate_EnterBytecodeDispatch(masm); |
| 908 } |
| 909 |
| 910 |
862 void Builtins::Generate_CompileLazy(MacroAssembler* masm) { | 911 void Builtins::Generate_CompileLazy(MacroAssembler* masm) { |
863 // ----------- S t a t e ------------- | 912 // ----------- S t a t e ------------- |
864 // -- rax : argument count (preserved for callee) | 913 // -- rax : argument count (preserved for callee) |
865 // -- rdx : new target (preserved for callee) | 914 // -- rdx : new target (preserved for callee) |
866 // -- rdi : target function (preserved for callee) | 915 // -- rdi : target function (preserved for callee) |
867 // ----------------------------------- | 916 // ----------------------------------- |
868 // First lookup code, maybe we don't need to compile! | 917 // First lookup code, maybe we don't need to compile! |
869 Label gotta_call_runtime; | 918 Label gotta_call_runtime; |
870 Label maybe_call_runtime; | 919 Label maybe_call_runtime; |
871 Label try_shared; | 920 Label try_shared; |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1125 | 1174 |
1126 __ CallRuntime(Runtime::kNotifyDeoptimized); | 1175 __ CallRuntime(Runtime::kNotifyDeoptimized); |
1127 // Tear down internal frame. | 1176 // Tear down internal frame. |
1128 } | 1177 } |
1129 | 1178 |
1130 // Get the full codegen state from the stack and untag it. | 1179 // Get the full codegen state from the stack and untag it. |
1131 __ SmiToInteger32(kScratchRegister, Operand(rsp, kPCOnStackSize)); | 1180 __ SmiToInteger32(kScratchRegister, Operand(rsp, kPCOnStackSize)); |
1132 | 1181 |
1133 // Switch on the state. | 1182 // Switch on the state. |
1134 Label not_no_registers, not_tos_rax; | 1183 Label not_no_registers, not_tos_rax; |
1135 __ cmpp(kScratchRegister, | 1184 __ cmpp(kScratchRegister, Immediate(FullCodeGenerator::NO_REGISTERS)); |
1136 Immediate(static_cast<int>(Deoptimizer::BailoutState::NO_REGISTERS))); | |
1137 __ j(not_equal, ¬_no_registers, Label::kNear); | 1185 __ j(not_equal, ¬_no_registers, Label::kNear); |
1138 __ ret(1 * kPointerSize); // Remove state. | 1186 __ ret(1 * kPointerSize); // Remove state. |
1139 | 1187 |
1140 __ bind(¬_no_registers); | 1188 __ bind(¬_no_registers); |
1141 DCHECK_EQ(kInterpreterAccumulatorRegister.code(), rax.code()); | |
1142 __ movp(rax, Operand(rsp, kPCOnStackSize + kPointerSize)); | 1189 __ movp(rax, Operand(rsp, kPCOnStackSize + kPointerSize)); |
1143 __ cmpp(kScratchRegister, | 1190 __ cmpp(kScratchRegister, Immediate(FullCodeGenerator::TOS_REG)); |
1144 Immediate(static_cast<int>(Deoptimizer::BailoutState::TOS_REGISTER))); | |
1145 __ j(not_equal, ¬_tos_rax, Label::kNear); | 1191 __ j(not_equal, ¬_tos_rax, Label::kNear); |
1146 __ ret(2 * kPointerSize); // Remove state, rax. | 1192 __ ret(2 * kPointerSize); // Remove state, rax. |
1147 | 1193 |
1148 __ bind(¬_tos_rax); | 1194 __ bind(¬_tos_rax); |
1149 __ Abort(kNoCasesLeft); | 1195 __ Abort(kNoCasesLeft); |
1150 } | 1196 } |
1151 | 1197 |
1152 | 1198 |
1153 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { | 1199 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { |
1154 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER); | 1200 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER); |
(...skipping 1754 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2909 __ ret(0); | 2955 __ ret(0); |
2910 } | 2956 } |
2911 | 2957 |
2912 | 2958 |
2913 #undef __ | 2959 #undef __ |
2914 | 2960 |
2915 } // namespace internal | 2961 } // namespace internal |
2916 } // namespace v8 | 2962 } // namespace v8 |
2917 | 2963 |
2918 #endif // V8_TARGET_ARCH_X64 | 2964 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |