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 685 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
696 // Push function as argument and compile for baseline. | 696 // Push function as argument and compile for baseline. |
697 __ push(edi); | 697 __ push(edi); |
698 __ CallRuntime(Runtime::kCompileBaseline); | 698 __ CallRuntime(Runtime::kCompileBaseline); |
699 | 699 |
700 // Restore return value. | 700 // Restore return value. |
701 __ pop(eax); | 701 __ pop(eax); |
702 } | 702 } |
703 __ ret(0); | 703 __ ret(0); |
704 } | 704 } |
705 | 705 |
| 706 static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, |
| 707 Register scratch1, Register scratch2, |
| 708 Label* stack_overflow, |
| 709 bool include_receiver = false) { |
| 710 // Check the stack for overflow. We are not trying to catch |
| 711 // interruptions (e.g. debug break and preemption) here, so the "real stack |
| 712 // limit" is checked. |
| 713 ExternalReference real_stack_limit = |
| 714 ExternalReference::address_of_real_stack_limit(masm->isolate()); |
| 715 __ mov(scratch1, Operand::StaticVariable(real_stack_limit)); |
| 716 // Make scratch2 the space we have left. The stack might already be overflowed |
| 717 // here which will cause scratch2 to become negative. |
| 718 __ mov(scratch2, esp); |
| 719 __ sub(scratch2, scratch1); |
| 720 // Make scratch1 the space we need for the array when it is unrolled onto the |
| 721 // stack. |
| 722 __ mov(scratch1, num_args); |
| 723 if (include_receiver) { |
| 724 __ add(scratch1, Immediate(1)); |
| 725 } |
| 726 __ shl(scratch1, kPointerSizeLog2); |
| 727 // Check if the arguments will overflow the stack. |
| 728 __ cmp(scratch2, scratch1); |
| 729 __ j(less_equal, stack_overflow); // Signed comparison. |
| 730 } |
| 731 |
706 static void Generate_InterpreterPushArgs(MacroAssembler* masm, | 732 static void Generate_InterpreterPushArgs(MacroAssembler* masm, |
707 Register array_limit, | 733 Register array_limit, |
708 Register start_address) { | 734 Register start_address) { |
709 // ----------- S t a t e ------------- | 735 // ----------- S t a t e ------------- |
710 // -- start_address : Pointer to the last argument in the args array. | 736 // -- start_address : Pointer to the last argument in the args array. |
711 // -- array_limit : Pointer to one before the first argument in the | 737 // -- array_limit : Pointer to one before the first argument in the |
712 // args array. | 738 // args array. |
713 // ----------------------------------- | 739 // ----------------------------------- |
714 Label loop_header, loop_check; | 740 Label loop_header, loop_check; |
715 __ jmp(&loop_check); | 741 __ jmp(&loop_check); |
716 __ bind(&loop_header); | 742 __ bind(&loop_header); |
717 __ Push(Operand(start_address, 0)); | 743 __ Push(Operand(start_address, 0)); |
718 __ sub(start_address, Immediate(kPointerSize)); | 744 __ sub(start_address, Immediate(kPointerSize)); |
719 __ bind(&loop_check); | 745 __ bind(&loop_check); |
720 __ cmp(start_address, array_limit); | 746 __ cmp(start_address, array_limit); |
721 __ j(greater, &loop_header, Label::kNear); | 747 __ j(greater, &loop_header, Label::kNear); |
722 } | 748 } |
723 | 749 |
724 // static | 750 // static |
725 void Builtins::Generate_InterpreterPushArgsAndCallImpl( | 751 void Builtins::Generate_InterpreterPushArgsAndCallImpl( |
726 MacroAssembler* masm, TailCallMode tail_call_mode, | 752 MacroAssembler* masm, TailCallMode tail_call_mode, |
727 CallableType function_type) { | 753 CallableType function_type) { |
728 // ----------- S t a t e ------------- | 754 // ----------- S t a t e ------------- |
729 // -- eax : the number of arguments (not including the receiver) | 755 // -- eax : the number of arguments (not including the receiver) |
730 // -- ebx : the address of the first argument to be pushed. Subsequent | 756 // -- ebx : the address of the first argument to be pushed. Subsequent |
731 // arguments should be consecutive above this, in the same order as | 757 // arguments should be consecutive above this, in the same order as |
732 // they are to be pushed onto the stack. | 758 // they are to be pushed onto the stack. |
733 // -- edi : the target to call (can be any Object). | 759 // -- edi : the target to call (can be any Object). |
734 // ----------------------------------- | 760 // ----------------------------------- |
| 761 Label stack_overflow; |
| 762 // Compute the expected number of arguments. |
| 763 __ mov(ecx, eax); |
| 764 __ add(ecx, Immediate(1)); // Add one for receiver. |
| 765 |
| 766 // Add a stack check before pushing the arguments. We need an extra register |
| 767 // to perform a stack check. So push it onto the stack temporarily. This |
| 768 // might cause stack overflow, but it will be detected by the check. |
| 769 __ Push(edi); |
| 770 Generate_StackOverflowCheck(masm, ecx, edx, edi, &stack_overflow); |
| 771 __ Pop(edi); |
735 | 772 |
736 // Pop return address to allow tail-call after pushing arguments. | 773 // Pop return address to allow tail-call after pushing arguments. |
737 __ Pop(edx); | 774 __ Pop(edx); |
738 | 775 |
739 // Find the address of the last argument. | 776 // Find the address of the last argument. |
740 __ mov(ecx, eax); | |
741 __ add(ecx, Immediate(1)); // Add one for receiver. | |
742 __ shl(ecx, kPointerSizeLog2); | 777 __ shl(ecx, kPointerSizeLog2); |
743 __ neg(ecx); | 778 __ neg(ecx); |
744 __ add(ecx, ebx); | 779 __ add(ecx, ebx); |
745 | |
746 // TODO(mythria): Add a stack check before pushing the arguments. | |
747 Generate_InterpreterPushArgs(masm, ecx, ebx); | 780 Generate_InterpreterPushArgs(masm, ecx, ebx); |
748 | 781 |
749 // Call the target. | 782 // Call the target. |
750 __ Push(edx); // Re-push return address. | 783 __ Push(edx); // Re-push return address. |
751 | 784 |
752 if (function_type == CallableType::kJSFunction) { | 785 if (function_type == CallableType::kJSFunction) { |
753 __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, | 786 __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, |
754 tail_call_mode), | 787 tail_call_mode), |
755 RelocInfo::CODE_TARGET); | 788 RelocInfo::CODE_TARGET); |
756 } else { | 789 } else { |
757 DCHECK_EQ(function_type, CallableType::kAny); | 790 DCHECK_EQ(function_type, CallableType::kAny); |
758 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, | 791 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, |
759 tail_call_mode), | 792 tail_call_mode), |
760 RelocInfo::CODE_TARGET); | 793 RelocInfo::CODE_TARGET); |
761 } | 794 } |
| 795 |
| 796 __ bind(&stack_overflow); |
| 797 { |
| 798 // Pop the temporary registers, so that return address is on top of stack. |
| 799 __ Pop(edi); |
| 800 |
| 801 __ TailCallRuntime(Runtime::kThrowStackOverflow); |
| 802 |
| 803 // This should be unreachable. |
| 804 __ int3(); |
| 805 } |
762 } | 806 } |
763 | 807 |
764 namespace { | 808 namespace { |
765 | 809 |
766 // This function modified start_addr, and only reads the contents of num_args | 810 // This function modified start_addr, and only reads the contents of num_args |
767 // register. scratch1 and scratch2 are used as temporary registers. Their | 811 // register. scratch1 and scratch2 are used as temporary registers. Their |
768 // original values are restored after the use. | 812 // original values are restored after the use. |
769 void Generate_InterpreterPushArgsAndReturnAddress( | 813 void Generate_InterpreterPushArgsAndReturnAddress( |
770 MacroAssembler* masm, Register num_args, Register start_addr, | 814 MacroAssembler* masm, Register num_args, Register start_addr, |
771 Register scratch1, Register scratch2, bool receiver_in_args) { | 815 Register scratch1, Register scratch2, bool receiver_in_args, |
772 // Store scratch2, scratch1 onto the stack. We need to restore the original | 816 int num_slots_above_ret_addr, Label* stack_overflow) { |
773 // values | 817 // We have to move return address and the temporary registers above it |
774 // so store scratch2, scratch1 temporarily on stack. | 818 // before we can copy arguments onto the stack. To achieve this: |
775 __ Push(scratch2); | 819 // Step 1: Increment the stack pointer by num_args + 1 (for receiver). |
776 __ Push(scratch1); | 820 // Step 2: Move the return address and values above it to the top of stack. |
777 | 821 // Step 3: Copy the arguments into the correct locations. |
778 // We have to pop return address and the two temporary registers before we | |
779 // can push arguments onto the stack. we do not have any free registers so | |
780 // update the stack and copy them into the correct places on the stack. | |
781 // current stack =====> required stack layout | 822 // current stack =====> required stack layout |
782 // | | | scratch1 | (2) <-- esp(1) | 823 // | | | scratch1 | (2) <-- esp(1) |
783 // | | | scratch2 | (3) | 824 // | | | .... | (2) |
784 // | | | return addr | (4) | 825 // | | | scratch-n | (2) |
785 // | | | arg N | (5) | 826 // | | | return addr | (2) |
| 827 // | | | arg N | (3) |
786 // | scratch1 | <-- esp | .... | | 828 // | scratch1 | <-- esp | .... | |
787 // | scratch2 | | arg 0 | | 829 // | .... | | arg 0 | |
| 830 // | scratch-n | | arg 0 | |
788 // | return addr | | receiver slot | | 831 // | return addr | | receiver slot | |
789 | 832 |
790 // First increment the stack pointer to the correct location. | 833 // Check for stack overflow before we increment the stack pointer. |
791 // we need additional slots for arguments and the receiver. | 834 Generate_StackOverflowCheck(masm, num_args, scratch1, scratch2, |
792 // Step 1 - compute the required increment to the stack. | 835 stack_overflow, true); |
793 __ mov(scratch1, num_args); | 836 |
794 __ shl(scratch1, kPointerSizeLog2); | 837 // Step 1 - Update the stack pointer. scratch1 already contains the required |
795 __ add(scratch1, Immediate(kPointerSize)); | 838 // increment to the stack. i.e. num_args + 1 stack slots. This is computed in |
| 839 // the Generate_StackOverflowCheck. |
796 | 840 |
797 #ifdef _MSC_VER | 841 #ifdef _MSC_VER |
798 // TODO(mythria): Move it to macro assembler. | 842 // TODO(mythria): Move it to macro assembler. |
799 // In windows, we cannot increment the stack size by more than one page | 843 // In windows, we cannot increment the stack size by more than one page |
800 // (mimimum page size is 4KB) without accessing at least one byte on the | 844 // (mimimum page size is 4KB) without accessing at least one byte on the |
801 // page. Check this: | 845 // page. Check this: |
802 // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. | 846 // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. |
803 const int page_size = 4 * 1024; | 847 const int page_size = 4 * 1024; |
804 Label check_offset, update_stack_pointer; | 848 Label check_offset, update_stack_pointer; |
805 __ bind(&check_offset); | 849 __ bind(&check_offset); |
806 __ cmp(scratch1, page_size); | 850 __ cmp(scratch1, page_size); |
807 __ j(less, &update_stack_pointer); | 851 __ j(less, &update_stack_pointer); |
808 __ sub(esp, Immediate(page_size)); | 852 __ sub(esp, Immediate(page_size)); |
809 // Just to touch the page, before we increment further. | 853 // Just to touch the page, before we increment further. |
810 __ mov(Operand(esp, 0), Immediate(0)); | 854 __ mov(Operand(esp, 0), Immediate(0)); |
811 __ sub(scratch1, Immediate(page_size)); | 855 __ sub(scratch1, Immediate(page_size)); |
812 __ jmp(&check_offset); | 856 __ jmp(&check_offset); |
813 __ bind(&update_stack_pointer); | 857 __ bind(&update_stack_pointer); |
814 #endif | 858 #endif |
815 | 859 |
816 // TODO(mythria): Add a stack check before updating the stack pointer. | |
817 | |
818 // Step 1 - Update the stack pointer. | |
819 __ sub(esp, scratch1); | 860 __ sub(esp, scratch1); |
820 | 861 |
821 // Step 2 move scratch1 to the correct location. Move scratch1 first otherwise | 862 // Step 2 move return_address and slots above it to the correct locations. |
822 // we may overwrite when num_args = 0 or 1, basically when the source and | 863 // Move from top to bottom, otherwise we may overwrite when num_args = 0 or 1, |
823 // destination overlap. We at least need one extra slot for receiver, | 864 // basically when the source and destination overlap. We at least need one |
824 // so no extra checks are required to avoid copy. | 865 // extra slot for receiver, so no extra checks are required to avoid copy. |
825 __ mov(scratch1, | 866 for (int i = 0; i < num_slots_above_ret_addr + 1; i++) { |
826 Operand(esp, num_args, times_pointer_size, 1 * kPointerSize)); | 867 __ mov(scratch1, |
827 __ mov(Operand(esp, 0), scratch1); | 868 Operand(esp, num_args, times_pointer_size, (i + 1) * kPointerSize)); |
| 869 __ mov(Operand(esp, i * kPointerSize), scratch1); |
| 870 } |
828 | 871 |
829 // Step 3 move scratch2 to the correct location | 872 // Step 3 copy arguments to correct locations. |
830 __ mov(scratch1, | |
831 Operand(esp, num_args, times_pointer_size, 2 * kPointerSize)); | |
832 __ mov(Operand(esp, 1 * kPointerSize), scratch1); | |
833 | |
834 // Step 4 move return address to the correct location | |
835 __ mov(scratch1, | |
836 Operand(esp, num_args, times_pointer_size, 3 * kPointerSize)); | |
837 __ mov(Operand(esp, 2 * kPointerSize), scratch1); | |
838 | |
839 // Step 5 copy arguments to correct locations. | |
840 if (receiver_in_args) { | 873 if (receiver_in_args) { |
841 __ mov(scratch1, num_args); | 874 __ mov(scratch1, num_args); |
842 __ add(scratch1, Immediate(1)); | 875 __ add(scratch1, Immediate(1)); |
843 } else { | 876 } else { |
844 // Slot meant for receiver contains return address. Reset it so that | 877 // Slot meant for receiver contains return address. Reset it so that |
845 // we will not incorrectly interpret return address as an object. | 878 // we will not incorrectly interpret return address as an object. |
846 __ mov(Operand(esp, num_args, times_pointer_size, 3 * kPointerSize), | 879 __ mov(Operand(esp, num_args, times_pointer_size, |
| 880 (num_slots_above_ret_addr + 1) * kPointerSize), |
847 Immediate(0)); | 881 Immediate(0)); |
848 __ mov(scratch1, num_args); | 882 __ mov(scratch1, num_args); |
849 } | 883 } |
850 | 884 |
851 Label loop_header, loop_check; | 885 Label loop_header, loop_check; |
852 __ jmp(&loop_check); | 886 __ jmp(&loop_check); |
853 __ bind(&loop_header); | 887 __ bind(&loop_header); |
854 __ mov(scratch2, Operand(start_addr, 0)); | 888 __ mov(scratch2, Operand(start_addr, 0)); |
855 __ mov(Operand(esp, scratch1, times_pointer_size, 2 * kPointerSize), | 889 __ mov(Operand(esp, scratch1, times_pointer_size, |
| 890 num_slots_above_ret_addr * kPointerSize), |
856 scratch2); | 891 scratch2); |
857 __ sub(start_addr, Immediate(kPointerSize)); | 892 __ sub(start_addr, Immediate(kPointerSize)); |
858 __ sub(scratch1, Immediate(1)); | 893 __ sub(scratch1, Immediate(1)); |
859 __ bind(&loop_check); | 894 __ bind(&loop_check); |
860 __ cmp(scratch1, Immediate(0)); | 895 __ cmp(scratch1, Immediate(0)); |
861 __ j(greater, &loop_header, Label::kNear); | 896 __ j(greater, &loop_header, Label::kNear); |
862 | |
863 // Restore scratch1 and scratch2. | |
864 __ Pop(scratch1); | |
865 __ Pop(scratch2); | |
866 } | 897 } |
867 | 898 |
868 } // end anonymous namespace | 899 } // end anonymous namespace |
869 | 900 |
870 // static | 901 // static |
871 void Builtins::Generate_InterpreterPushArgsAndConstructImpl( | 902 void Builtins::Generate_InterpreterPushArgsAndConstructImpl( |
872 MacroAssembler* masm, CallableType construct_type) { | 903 MacroAssembler* masm, CallableType construct_type) { |
873 // ----------- S t a t e ------------- | 904 // ----------- S t a t e ------------- |
874 // -- eax : the number of arguments (not including the receiver) | 905 // -- eax : the number of arguments (not including the receiver) |
875 // -- edx : the new target | 906 // -- edx : the new target |
876 // -- edi : the constructor | 907 // -- edi : the constructor |
877 // -- ebx : allocation site feedback (if available or undefined) | 908 // -- ebx : allocation site feedback (if available or undefined) |
878 // -- ecx : the address of the first argument to be pushed. Subsequent | 909 // -- ecx : the address of the first argument to be pushed. Subsequent |
879 // arguments should be consecutive above this, in the same order as | 910 // arguments should be consecutive above this, in the same order as |
880 // they are to be pushed onto the stack. | 911 // they are to be pushed onto the stack. |
881 // ----------------------------------- | 912 // ----------------------------------- |
| 913 Label stack_overflow; |
| 914 // We need two scratch registers. Push edi and edx onto stack. |
| 915 __ Push(edi); |
| 916 __ Push(edx); |
882 | 917 |
883 // Push arguments and move return address to the top of stack. | 918 // Push arguments and move return address to the top of stack. |
884 // The eax register is readonly. The ecx register will be modified. The edx | 919 // The eax register is readonly. The ecx register will be modified. The edx |
885 // and edi registers will be modified but restored to their original values. | 920 // and edi registers will be modified but restored to their original values. |
886 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false); | 921 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false, |
| 922 2, &stack_overflow); |
| 923 |
| 924 // Restore edi and edx |
| 925 __ Pop(edx); |
| 926 __ Pop(edi); |
887 | 927 |
888 __ AssertUndefinedOrAllocationSite(ebx); | 928 __ AssertUndefinedOrAllocationSite(ebx); |
889 if (construct_type == CallableType::kJSFunction) { | 929 if (construct_type == CallableType::kJSFunction) { |
890 // Tail call to the function-specific construct stub (still in the caller | 930 // Tail call to the function-specific construct stub (still in the caller |
891 // context at this point). | 931 // context at this point). |
892 __ AssertFunction(edi); | 932 __ AssertFunction(edi); |
893 | 933 |
894 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 934 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
895 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); | 935 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); |
896 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); | 936 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); |
897 __ jmp(ecx); | 937 __ jmp(ecx); |
898 } else { | 938 } else { |
899 DCHECK_EQ(construct_type, CallableType::kAny); | 939 DCHECK_EQ(construct_type, CallableType::kAny); |
900 | 940 |
901 // Call the constructor with unmodified eax, edi, edx values. | 941 // Call the constructor with unmodified eax, edi, edx values. |
902 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 942 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
903 } | 943 } |
| 944 |
| 945 __ bind(&stack_overflow); |
| 946 { |
| 947 // Pop the temporary registers, so that return address is on top of stack. |
| 948 __ Pop(edx); |
| 949 __ Pop(edi); |
| 950 |
| 951 __ TailCallRuntime(Runtime::kThrowStackOverflow); |
| 952 |
| 953 // This should be unreachable. |
| 954 __ int3(); |
| 955 } |
904 } | 956 } |
905 | 957 |
906 // static | 958 // static |
907 void Builtins::Generate_InterpreterPushArgsAndConstructArray( | 959 void Builtins::Generate_InterpreterPushArgsAndConstructArray( |
908 MacroAssembler* masm) { | 960 MacroAssembler* masm) { |
909 // ----------- S t a t e ------------- | 961 // ----------- S t a t e ------------- |
910 // -- eax : the number of arguments (not including the receiver) | 962 // -- eax : the number of arguments (not including the receiver) |
911 // -- edx : the target to call checked to be Array function. | 963 // -- edx : the target to call checked to be Array function. |
912 // -- ebx : the allocation site feedback | 964 // -- ebx : the allocation site feedback |
913 // -- ecx : the address of the first argument to be pushed. Subsequent | 965 // -- ecx : the address of the first argument to be pushed. Subsequent |
914 // arguments should be consecutive above this, in the same order as | 966 // arguments should be consecutive above this, in the same order as |
915 // they are to be pushed onto the stack. | 967 // they are to be pushed onto the stack. |
916 // ----------------------------------- | 968 // ----------------------------------- |
| 969 Label stack_overflow; |
| 970 // We need two scratch registers. Register edi is available, push edx onto |
| 971 // stack. |
| 972 __ Push(edx); |
917 | 973 |
918 // Push arguments and move return address to the top of stack. | 974 // Push arguments and move return address to the top of stack. |
919 // The eax register is readonly. The ecx register will be modified. The edx | 975 // The eax register is readonly. The ecx register will be modified. The edx |
920 // and edi registers will be modified but restored to their original values. | 976 // and edi registers will be modified but restored to their original values. |
921 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, ebx, true); | 977 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, true, |
| 978 1, &stack_overflow); |
| 979 |
| 980 // Restore edx. |
| 981 __ Pop(edx); |
922 | 982 |
923 // Array constructor expects constructor in edi. It is same as edx here. | 983 // Array constructor expects constructor in edi. It is same as edx here. |
924 __ Move(edi, edx); | 984 __ Move(edi, edx); |
925 | 985 |
926 ArrayConstructorStub stub(masm->isolate()); | 986 ArrayConstructorStub stub(masm->isolate()); |
927 __ TailCallStub(&stub); | 987 __ TailCallStub(&stub); |
| 988 |
| 989 __ bind(&stack_overflow); |
| 990 { |
| 991 // Pop the temporary registers, so that return address is on top of stack. |
| 992 __ Pop(edx); |
| 993 |
| 994 __ TailCallRuntime(Runtime::kThrowStackOverflow); |
| 995 |
| 996 // This should be unreachable. |
| 997 __ int3(); |
| 998 } |
928 } | 999 } |
929 | 1000 |
930 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { | 1001 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { |
931 // Set the return address to the correct point in the interpreter entry | 1002 // Set the return address to the correct point in the interpreter entry |
932 // trampoline. | 1003 // trampoline. |
933 Smi* interpreter_entry_return_pc_offset( | 1004 Smi* interpreter_entry_return_pc_offset( |
934 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); | 1005 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); |
935 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); | 1006 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); |
936 __ LoadHeapObject(ebx, | 1007 __ LoadHeapObject(ebx, |
937 masm->isolate()->builtins()->InterpreterEntryTrampoline()); | 1008 masm->isolate()->builtins()->InterpreterEntryTrampoline()); |
(...skipping 1205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2143 __ bind(&drop_frame_and_ret); | 2214 __ bind(&drop_frame_and_ret); |
2144 { | 2215 { |
2145 // Drop all arguments including the receiver. | 2216 // Drop all arguments including the receiver. |
2146 __ PopReturnAddressTo(ecx); | 2217 __ PopReturnAddressTo(ecx); |
2147 __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); | 2218 __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); |
2148 __ PushReturnAddressFrom(ecx); | 2219 __ PushReturnAddressFrom(ecx); |
2149 __ Ret(); | 2220 __ Ret(); |
2150 } | 2221 } |
2151 } | 2222 } |
2152 | 2223 |
2153 static void ArgumentsAdaptorStackCheck(MacroAssembler* masm, | |
2154 Label* stack_overflow) { | |
2155 // ----------- S t a t e ------------- | |
2156 // -- eax : actual number of arguments | |
2157 // -- ebx : expected number of arguments | |
2158 // -- edx : new target (passed through to callee) | |
2159 // ----------------------------------- | |
2160 // Check the stack for overflow. We are not trying to catch | |
2161 // interruptions (e.g. debug break and preemption) here, so the "real stack | |
2162 // limit" is checked. | |
2163 ExternalReference real_stack_limit = | |
2164 ExternalReference::address_of_real_stack_limit(masm->isolate()); | |
2165 __ mov(edi, Operand::StaticVariable(real_stack_limit)); | |
2166 // Make ecx the space we have left. The stack might already be overflowed | |
2167 // here which will cause ecx to become negative. | |
2168 __ mov(ecx, esp); | |
2169 __ sub(ecx, edi); | |
2170 // Make edi the space we need for the array when it is unrolled onto the | |
2171 // stack. | |
2172 __ mov(edi, ebx); | |
2173 __ shl(edi, kPointerSizeLog2); | |
2174 // Check if the arguments will overflow the stack. | |
2175 __ cmp(ecx, edi); | |
2176 __ j(less_equal, stack_overflow); // Signed comparison. | |
2177 } | |
2178 | |
2179 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { | 2224 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { |
2180 __ push(ebp); | 2225 __ push(ebp); |
2181 __ mov(ebp, esp); | 2226 __ mov(ebp, esp); |
2182 | 2227 |
2183 // Store the arguments adaptor context sentinel. | 2228 // Store the arguments adaptor context sentinel. |
2184 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2229 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
2185 | 2230 |
2186 // Push the function on the stack. | 2231 // Push the function on the stack. |
2187 __ push(edi); | 2232 __ push(edi); |
2188 | 2233 |
(...skipping 726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2915 | 2960 |
2916 Label enough, too_few; | 2961 Label enough, too_few; |
2917 __ cmp(eax, ebx); | 2962 __ cmp(eax, ebx); |
2918 __ j(less, &too_few); | 2963 __ j(less, &too_few); |
2919 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); | 2964 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
2920 __ j(equal, &dont_adapt_arguments); | 2965 __ j(equal, &dont_adapt_arguments); |
2921 | 2966 |
2922 { // Enough parameters: Actual >= expected. | 2967 { // Enough parameters: Actual >= expected. |
2923 __ bind(&enough); | 2968 __ bind(&enough); |
2924 EnterArgumentsAdaptorFrame(masm); | 2969 EnterArgumentsAdaptorFrame(masm); |
2925 ArgumentsAdaptorStackCheck(masm, &stack_overflow); | 2970 // edi is used as a scratch register. It should be restored from the frame |
| 2971 // when needed. |
| 2972 Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); |
2926 | 2973 |
2927 // Copy receiver and all expected arguments. | 2974 // Copy receiver and all expected arguments. |
2928 const int offset = StandardFrameConstants::kCallerSPOffset; | 2975 const int offset = StandardFrameConstants::kCallerSPOffset; |
2929 __ lea(edi, Operand(ebp, eax, times_4, offset)); | 2976 __ lea(edi, Operand(ebp, eax, times_4, offset)); |
2930 __ mov(eax, -1); // account for receiver | 2977 __ mov(eax, -1); // account for receiver |
2931 | 2978 |
2932 Label copy; | 2979 Label copy; |
2933 __ bind(©); | 2980 __ bind(©); |
2934 __ inc(eax); | 2981 __ inc(eax); |
2935 __ push(Operand(edi, 0)); | 2982 __ push(Operand(edi, 0)); |
2936 __ sub(edi, Immediate(kPointerSize)); | 2983 __ sub(edi, Immediate(kPointerSize)); |
2937 __ cmp(eax, ebx); | 2984 __ cmp(eax, ebx); |
2938 __ j(less, ©); | 2985 __ j(less, ©); |
2939 // eax now contains the expected number of arguments. | 2986 // eax now contains the expected number of arguments. |
2940 __ jmp(&invoke); | 2987 __ jmp(&invoke); |
2941 } | 2988 } |
2942 | 2989 |
2943 { // Too few parameters: Actual < expected. | 2990 { // Too few parameters: Actual < expected. |
2944 __ bind(&too_few); | 2991 __ bind(&too_few); |
2945 EnterArgumentsAdaptorFrame(masm); | 2992 EnterArgumentsAdaptorFrame(masm); |
2946 ArgumentsAdaptorStackCheck(masm, &stack_overflow); | 2993 // edi is used as a scratch register. It should be restored from the frame |
| 2994 // when needed. |
| 2995 Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); |
2947 | 2996 |
2948 // Remember expected arguments in ecx. | 2997 // Remember expected arguments in ecx. |
2949 __ mov(ecx, ebx); | 2998 __ mov(ecx, ebx); |
2950 | 2999 |
2951 // Copy receiver and all actual arguments. | 3000 // Copy receiver and all actual arguments. |
2952 const int offset = StandardFrameConstants::kCallerSPOffset; | 3001 const int offset = StandardFrameConstants::kCallerSPOffset; |
2953 __ lea(edi, Operand(ebp, eax, times_4, offset)); | 3002 __ lea(edi, Operand(ebp, eax, times_4, offset)); |
2954 // ebx = expected - actual. | 3003 // ebx = expected - actual. |
2955 __ sub(ebx, eax); | 3004 __ sub(ebx, eax); |
2956 // eax = -actual - 1 | 3005 // eax = -actual - 1 |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3171 | 3220 |
3172 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { | 3221 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { |
3173 Generate_OnStackReplacementHelper(masm, true); | 3222 Generate_OnStackReplacementHelper(masm, true); |
3174 } | 3223 } |
3175 | 3224 |
3176 #undef __ | 3225 #undef __ |
3177 } // namespace internal | 3226 } // namespace internal |
3178 } // namespace v8 | 3227 } // namespace v8 |
3179 | 3228 |
3180 #endif // V8_TARGET_ARCH_IA32 | 3229 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |