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_X87 | 5 #if V8_TARGET_ARCH_X87 |
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 744 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
755 tail_call_mode), | 755 tail_call_mode), |
756 RelocInfo::CODE_TARGET); | 756 RelocInfo::CODE_TARGET); |
757 } else { | 757 } else { |
758 DCHECK_EQ(function_type, CallableType::kAny); | 758 DCHECK_EQ(function_type, CallableType::kAny); |
759 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, | 759 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, |
760 tail_call_mode), | 760 tail_call_mode), |
761 RelocInfo::CODE_TARGET); | 761 RelocInfo::CODE_TARGET); |
762 } | 762 } |
763 } | 763 } |
764 | 764 |
765 // static | 765 namespace { |
766 void Builtins::Generate_InterpreterPushArgsAndConstructImpl( | |
767 MacroAssembler* masm, CallableType construct_type) { | |
768 // ----------- S t a t e ------------- | |
769 // -- eax : the number of arguments (not including the receiver) | |
770 // -- edx : the new target | |
771 // -- edi : the constructor | |
772 // -- ebx : allocation site feedback (if available or undefined) | |
773 // -- ecx : the address of the first argument to be pushed. Subsequent | |
774 // arguments should be consecutive above this, in the same order as | |
775 // they are to be pushed onto the stack. | |
776 // ----------------------------------- | |
777 | 766 |
778 // Store edi, edx onto the stack. We need two extra registers | 767 // This function modified start_addr, and only reads the contents of num_args |
779 // so store edi, edx temporarily on stack. | 768 // register. scratch1 and scratch2 are used as temporary registers. Their |
780 __ Push(edi); | 769 // original values are restored after the use. |
781 __ Push(edx); | 770 void Generate_InterpreterPushArgsAndReturnAddress( |
| 771 MacroAssembler* masm, Register num_args, Register start_addr, |
| 772 Register scratch1, Register scratch2, bool receiver_in_args) { |
| 773 // Store scratch2, scratch1 onto the stack. We need to restore the original |
| 774 // values |
| 775 // so store scratch2, scratch1 temporarily on stack. |
| 776 __ Push(scratch2); |
| 777 __ Push(scratch1); |
782 | 778 |
783 // We have to pop return address and the two temporary registers before we | 779 // We have to pop return address and the two temporary registers before we |
784 // can push arguments onto the stack. we do not have any free registers so | 780 // can push arguments onto the stack. we do not have any free registers so |
785 // update the stack and copy them into the correct places on the stack. | 781 // update the stack and copy them into the correct places on the stack. |
786 // current stack =====> required stack layout | 782 // current stack =====> required stack layout |
787 // | | | edx | (2) <-- esp(1) | 783 // | | | scratch1 | (2) <-- esp(1) |
788 // | | | edi | (3) | 784 // | | | scratch2 | (3) |
789 // | | | return addr | (4) | 785 // | | | return addr | (4) |
790 // | | | arg N | (5) | 786 // | | | arg N | (5) |
791 // | edx | <-- esp | .... | | 787 // | scratch1 | <-- esp | .... | |
792 // | edi | | arg 0 | | 788 // | scratch2 | | arg 0 | |
793 // | return addr | | receiver slot | | 789 // | return addr | | receiver slot | |
794 | 790 |
795 // First increment the stack pointer to the correct location. | 791 // First increment the stack pointer to the correct location. |
796 // we need additional slots for arguments and the receiver. | 792 // we need additional slots for arguments and the receiver. |
797 // Step 1 - compute the required increment to the stack. | 793 // Step 1 - compute the required increment to the stack. |
798 __ mov(edx, eax); | 794 __ mov(scratch1, num_args); |
799 __ shl(edx, kPointerSizeLog2); | 795 __ shl(scratch1, kPointerSizeLog2); |
800 __ add(edx, Immediate(kPointerSize)); | 796 __ add(scratch1, Immediate(kPointerSize)); |
801 | 797 |
802 #ifdef _MSC_VER | 798 #ifdef _MSC_VER |
803 // TODO(mythria): Move it to macro assembler. | 799 // TODO(mythria): Move it to macro assembler. |
804 // In windows, we cannot increment the stack size by more than one page | 800 // In windows, we cannot increment the stack size by more than one page |
805 // (mimimum page size is 4KB) without accessing at least one byte on the | 801 // (mimimum page size is 4KB) without accessing at least one byte on the |
806 // page. Check this: | 802 // page. Check this: |
807 // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. | 803 // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. |
808 const int page_size = 4 * 1024; | 804 const int page_size = 4 * 1024; |
809 Label check_offset, update_stack_pointer; | 805 Label check_offset, update_stack_pointer; |
810 __ bind(&check_offset); | 806 __ bind(&check_offset); |
811 __ cmp(edx, page_size); | 807 __ cmp(scratch1, page_size); |
812 __ j(less, &update_stack_pointer); | 808 __ j(less, &update_stack_pointer); |
813 __ sub(esp, Immediate(page_size)); | 809 __ sub(esp, Immediate(page_size)); |
814 // Just to touch the page, before we increment further. | 810 // Just to touch the page, before we increment further. |
815 __ mov(Operand(esp, 0), Immediate(0)); | 811 __ mov(Operand(esp, 0), Immediate(0)); |
816 __ sub(edx, Immediate(page_size)); | 812 __ sub(scratch1, Immediate(page_size)); |
817 __ jmp(&check_offset); | 813 __ jmp(&check_offset); |
818 __ bind(&update_stack_pointer); | 814 __ bind(&update_stack_pointer); |
819 #endif | 815 #endif |
820 | 816 |
821 // TODO(mythria): Add a stack check before updating the stack pointer. | 817 // TODO(mythria): Add a stack check before updating the stack pointer. |
822 | 818 |
823 // Step 1 - Update the stack pointer. | 819 // Step 1 - Update the stack pointer. |
824 __ sub(esp, edx); | 820 __ sub(esp, scratch1); |
825 | 821 |
826 // Step 2 move edx to the correct location. Move edx first otherwise | 822 // Step 2 move scratch1 to the correct location. Move scratch1 first otherwise |
827 // we may overwrite when eax = 0 or 1, basically when the source and | 823 // we may overwrite when num_args = 0 or 1, basically when the source and |
828 // destination overlap. We at least need one extra slot for receiver, | 824 // destination overlap. We at least need one extra slot for receiver, |
829 // so no extra checks are required to avoid copy. | 825 // so no extra checks are required to avoid copy. |
830 __ mov(edi, Operand(esp, eax, times_pointer_size, 1 * kPointerSize)); | 826 __ mov(scratch1, |
831 __ mov(Operand(esp, 0), edi); | 827 Operand(esp, num_args, times_pointer_size, 1 * kPointerSize)); |
| 828 __ mov(Operand(esp, 0), scratch1); |
832 | 829 |
833 // Step 3 move edi to the correct location | 830 // Step 3 move scratch2 to the correct location |
834 __ mov(edi, Operand(esp, eax, times_pointer_size, 2 * kPointerSize)); | 831 __ mov(scratch1, |
835 __ mov(Operand(esp, 1 * kPointerSize), edi); | 832 Operand(esp, num_args, times_pointer_size, 2 * kPointerSize)); |
| 833 __ mov(Operand(esp, 1 * kPointerSize), scratch1); |
836 | 834 |
837 // Step 4 move return address to the correct location | 835 // Step 4 move return address to the correct location |
838 __ mov(edi, Operand(esp, eax, times_pointer_size, 3 * kPointerSize)); | 836 __ mov(scratch1, |
839 __ mov(Operand(esp, 2 * kPointerSize), edi); | 837 Operand(esp, num_args, times_pointer_size, 3 * kPointerSize)); |
840 | 838 __ mov(Operand(esp, 2 * kPointerSize), scratch1); |
841 // Slot meant for receiver contains return address. Reset it so that | |
842 // we will not incorrectly interpret return address as an object. | |
843 __ mov(Operand(esp, eax, times_pointer_size, 3 * kPointerSize), Immediate(0)); | |
844 | 839 |
845 // Step 5 copy arguments to correct locations. | 840 // Step 5 copy arguments to correct locations. |
846 __ mov(edx, eax); | 841 if (receiver_in_args) { |
| 842 __ mov(scratch1, num_args); |
| 843 __ add(scratch1, Immediate(1)); |
| 844 } else { |
| 845 // Slot meant for receiver contains return address. Reset it so that |
| 846 // we will not incorrectly interpret return address as an object. |
| 847 __ mov(Operand(esp, num_args, times_pointer_size, 3 * kPointerSize), |
| 848 Immediate(0)); |
| 849 __ mov(scratch1, num_args); |
| 850 } |
847 | 851 |
848 Label loop_header, loop_check; | 852 Label loop_header, loop_check; |
849 __ jmp(&loop_check); | 853 __ jmp(&loop_check); |
850 __ bind(&loop_header); | 854 __ bind(&loop_header); |
851 __ mov(edi, Operand(ecx, 0)); | 855 __ mov(scratch2, Operand(start_addr, 0)); |
852 __ mov(Operand(esp, edx, times_pointer_size, 2 * kPointerSize), edi); | 856 __ mov(Operand(esp, scratch1, times_pointer_size, 2 * kPointerSize), |
853 __ sub(ecx, Immediate(kPointerSize)); | 857 scratch2); |
854 __ sub(edx, Immediate(1)); | 858 __ sub(start_addr, Immediate(kPointerSize)); |
| 859 __ sub(scratch1, Immediate(1)); |
855 __ bind(&loop_check); | 860 __ bind(&loop_check); |
856 __ cmp(edx, Immediate(0)); | 861 __ cmp(scratch1, Immediate(0)); |
857 __ j(greater, &loop_header, Label::kNear); | 862 __ j(greater, &loop_header, Label::kNear); |
858 | 863 |
859 // Restore edi and edx. | 864 // Restore scratch1 and scratch2. |
860 __ Pop(edx); | 865 __ Pop(scratch1); |
861 __ Pop(edi); | 866 __ Pop(scratch2); |
| 867 } |
| 868 |
| 869 } // end anonymous namespace |
| 870 |
| 871 // static |
| 872 void Builtins::Generate_InterpreterPushArgsAndConstructImpl( |
| 873 MacroAssembler* masm, CallableType construct_type) { |
| 874 // ----------- S t a t e ------------- |
| 875 // -- eax : the number of arguments (not including the receiver) |
| 876 // -- edx : the new target |
| 877 // -- edi : the constructor |
| 878 // -- ebx : allocation site feedback (if available or undefined) |
| 879 // -- ecx : the address of the first argument to be pushed. Subsequent |
| 880 // arguments should be consecutive above this, in the same order as |
| 881 // they are to be pushed onto the stack. |
| 882 // ----------------------------------- |
| 883 |
| 884 // Push arguments and move return address to the top of stack. |
| 885 // The eax register is readonly. The ecx register will be modified. The edx |
| 886 // and edi registers will be modified but restored to their original values. |
| 887 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false); |
862 | 888 |
863 __ AssertUndefinedOrAllocationSite(ebx); | 889 __ AssertUndefinedOrAllocationSite(ebx); |
864 if (construct_type == CallableType::kJSFunction) { | 890 if (construct_type == CallableType::kJSFunction) { |
865 // Tail call to the function-specific construct stub (still in the caller | 891 // Tail call to the function-specific construct stub (still in the caller |
866 // context at this point). | 892 // context at this point). |
867 __ AssertFunction(edi); | 893 __ AssertFunction(edi); |
868 | 894 |
869 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 895 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
870 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); | 896 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); |
871 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); | 897 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); |
872 __ jmp(ecx); | 898 __ jmp(ecx); |
873 } else { | 899 } else { |
874 DCHECK_EQ(construct_type, CallableType::kAny); | 900 DCHECK_EQ(construct_type, CallableType::kAny); |
875 | 901 |
876 // Call the constructor with unmodified eax, edi, edx values. | 902 // Call the constructor with unmodified eax, edi, edx values. |
877 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 903 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
878 } | 904 } |
879 } | 905 } |
880 | 906 |
| 907 // static |
| 908 void Builtins::Generate_InterpreterPushArgsAndConstructArray( |
| 909 MacroAssembler* masm) { |
| 910 // ----------- S t a t e ------------- |
| 911 // -- eax : the number of arguments (not including the receiver) |
| 912 // -- edx : the target to call checked to be Array function. |
| 913 // -- ebx : the allocation site feedback |
| 914 // -- ecx : the address of the first argument to be pushed. Subsequent |
| 915 // arguments should be consecutive above this, in the same order as |
| 916 // they are to be pushed onto the stack. |
| 917 // ----------------------------------- |
| 918 |
| 919 // Push arguments and move return address to the top of stack. |
| 920 // The eax register is readonly. The ecx register will be modified. The edx |
| 921 // and edi registers will be modified but restored to their original values. |
| 922 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, ebx, true); |
| 923 |
| 924 // Array constructor expects constructor in edi. It is same as edx here. |
| 925 __ Move(edi, edx); |
| 926 |
| 927 ArrayConstructorStub stub(masm->isolate()); |
| 928 __ TailCallStub(&stub); |
| 929 } |
| 930 |
881 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { | 931 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { |
882 // Set the return address to the correct point in the interpreter entry | 932 // Set the return address to the correct point in the interpreter entry |
883 // trampoline. | 933 // trampoline. |
884 Smi* interpreter_entry_return_pc_offset( | 934 Smi* interpreter_entry_return_pc_offset( |
885 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); | 935 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); |
886 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); | 936 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); |
887 __ LoadHeapObject(ebx, | 937 __ LoadHeapObject(ebx, |
888 masm->isolate()->builtins()->InterpreterEntryTrampoline()); | 938 masm->isolate()->builtins()->InterpreterEntryTrampoline()); |
889 __ add(ebx, Immediate(interpreter_entry_return_pc_offset->value() + | 939 __ add(ebx, Immediate(interpreter_entry_return_pc_offset->value() + |
890 Code::kHeaderSize - kHeapObjectTag)); | 940 Code::kHeaderSize - kHeapObjectTag)); |
(...skipping 2255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3146 | 3196 |
3147 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { | 3197 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { |
3148 Generate_OnStackReplacementHelper(masm, true); | 3198 Generate_OnStackReplacementHelper(masm, true); |
3149 } | 3199 } |
3150 | 3200 |
3151 #undef __ | 3201 #undef __ |
3152 } // namespace internal | 3202 } // namespace internal |
3153 } // namespace v8 | 3203 } // namespace v8 |
3154 | 3204 |
3155 #endif // V8_TARGET_ARCH_X87 | 3205 #endif // V8_TARGET_ARCH_X87 |
OLD | NEW |