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