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