| 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 693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 704 // Push function as argument and compile for baseline. | 704 // Push function as argument and compile for baseline. |
| 705 __ push(edi); | 705 __ push(edi); |
| 706 __ CallRuntime(Runtime::kCompileBaseline); | 706 __ CallRuntime(Runtime::kCompileBaseline); |
| 707 | 707 |
| 708 // Restore return value. | 708 // Restore return value. |
| 709 __ pop(eax); | 709 __ pop(eax); |
| 710 } | 710 } |
| 711 __ ret(0); | 711 __ ret(0); |
| 712 } | 712 } |
| 713 | 713 |
| 714 static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, |
| 715 Register scratch1, Register scratch2, |
| 716 Label* stack_overflow, |
| 717 bool include_receiver = false) { |
| 718 // Check the stack for overflow. We are not trying to catch |
| 719 // interruptions (e.g. debug break and preemption) here, so the "real stack |
| 720 // limit" is checked. |
| 721 ExternalReference real_stack_limit = |
| 722 ExternalReference::address_of_real_stack_limit(masm->isolate()); |
| 723 __ mov(scratch1, Operand::StaticVariable(real_stack_limit)); |
| 724 // Make scratch2 the space we have left. The stack might already be overflowed |
| 725 // here which will cause scratch2 to become negative. |
| 726 __ mov(scratch2, esp); |
| 727 __ sub(scratch2, scratch1); |
| 728 // Make scratch1 the space we need for the array when it is unrolled onto the |
| 729 // stack. |
| 730 __ mov(scratch1, num_args); |
| 731 if (include_receiver) { |
| 732 __ add(scratch1, Immediate(1)); |
| 733 } |
| 734 __ shl(scratch1, kPointerSizeLog2); |
| 735 // Check if the arguments will overflow the stack. |
| 736 __ cmp(scratch2, scratch1); |
| 737 __ j(less_equal, stack_overflow); // Signed comparison. |
| 738 } |
| 739 |
| 714 static void Generate_InterpreterPushArgs(MacroAssembler* masm, | 740 static void Generate_InterpreterPushArgs(MacroAssembler* masm, |
| 715 Register array_limit, | 741 Register array_limit, |
| 716 Register start_address) { | 742 Register start_address) { |
| 717 // ----------- S t a t e ------------- | 743 // ----------- S t a t e ------------- |
| 718 // -- start_address : Pointer to the last argument in the args array. | 744 // -- start_address : Pointer to the last argument in the args array. |
| 719 // -- array_limit : Pointer to one before the first argument in the | 745 // -- array_limit : Pointer to one before the first argument in the |
| 720 // args array. | 746 // args array. |
| 721 // ----------------------------------- | 747 // ----------------------------------- |
| 722 Label loop_header, loop_check; | 748 Label loop_header, loop_check; |
| 723 __ jmp(&loop_check); | 749 __ jmp(&loop_check); |
| 724 __ bind(&loop_header); | 750 __ bind(&loop_header); |
| 725 __ Push(Operand(start_address, 0)); | 751 __ Push(Operand(start_address, 0)); |
| 726 __ sub(start_address, Immediate(kPointerSize)); | 752 __ sub(start_address, Immediate(kPointerSize)); |
| 727 __ bind(&loop_check); | 753 __ bind(&loop_check); |
| 728 __ cmp(start_address, array_limit); | 754 __ cmp(start_address, array_limit); |
| 729 __ j(greater, &loop_header, Label::kNear); | 755 __ j(greater, &loop_header, Label::kNear); |
| 730 } | 756 } |
| 731 | 757 |
| 732 // static | 758 // static |
| 733 void Builtins::Generate_InterpreterPushArgsAndCallImpl( | 759 void Builtins::Generate_InterpreterPushArgsAndCallImpl( |
| 734 MacroAssembler* masm, TailCallMode tail_call_mode, | 760 MacroAssembler* masm, TailCallMode tail_call_mode, |
| 735 CallableType function_type) { | 761 CallableType function_type) { |
| 736 // ----------- S t a t e ------------- | 762 // ----------- S t a t e ------------- |
| 737 // -- eax : the number of arguments (not including the receiver) | 763 // -- eax : the number of arguments (not including the receiver) |
| 738 // -- ebx : the address of the first argument to be pushed. Subsequent | 764 // -- ebx : the address of the first argument to be pushed. Subsequent |
| 739 // arguments should be consecutive above this, in the same order as | 765 // arguments should be consecutive above this, in the same order as |
| 740 // they are to be pushed onto the stack. | 766 // they are to be pushed onto the stack. |
| 741 // -- edi : the target to call (can be any Object). | 767 // -- edi : the target to call (can be any Object). |
| 742 // ----------------------------------- | 768 // ----------------------------------- |
| 769 Label stack_overflow; |
| 770 // Compute the expected number of arguments. |
| 771 __ mov(ecx, eax); |
| 772 __ add(ecx, Immediate(1)); // Add one for receiver. |
| 773 |
| 774 // Add a stack check before pushing the arguments. We need an extra register |
| 775 // to perform a stack check. So push it onto the stack temporarily. This |
| 776 // might cause stack overflow, but it will be detected by the check. |
| 777 __ Push(edi); |
| 778 Generate_StackOverflowCheck(masm, ecx, edx, edi, &stack_overflow); |
| 779 __ Pop(edi); |
| 743 | 780 |
| 744 // Pop return address to allow tail-call after pushing arguments. | 781 // Pop return address to allow tail-call after pushing arguments. |
| 745 __ Pop(edx); | 782 __ Pop(edx); |
| 746 | 783 |
| 747 // Find the address of the last argument. | 784 // Find the address of the last argument. |
| 748 __ mov(ecx, eax); | |
| 749 __ add(ecx, Immediate(1)); // Add one for receiver. | |
| 750 __ shl(ecx, kPointerSizeLog2); | 785 __ shl(ecx, kPointerSizeLog2); |
| 751 __ neg(ecx); | 786 __ neg(ecx); |
| 752 __ add(ecx, ebx); | 787 __ add(ecx, ebx); |
| 753 | |
| 754 // TODO(mythria): Add a stack check before pushing the arguments. | |
| 755 Generate_InterpreterPushArgs(masm, ecx, ebx); | 788 Generate_InterpreterPushArgs(masm, ecx, ebx); |
| 756 | 789 |
| 757 // Call the target. | 790 // Call the target. |
| 758 __ Push(edx); // Re-push return address. | 791 __ Push(edx); // Re-push return address. |
| 759 | 792 |
| 760 if (function_type == CallableType::kJSFunction) { | 793 if (function_type == CallableType::kJSFunction) { |
| 761 __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, | 794 __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, |
| 762 tail_call_mode), | 795 tail_call_mode), |
| 763 RelocInfo::CODE_TARGET); | 796 RelocInfo::CODE_TARGET); |
| 764 } else { | 797 } else { |
| 765 DCHECK_EQ(function_type, CallableType::kAny); | 798 DCHECK_EQ(function_type, CallableType::kAny); |
| 766 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, | 799 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, |
| 767 tail_call_mode), | 800 tail_call_mode), |
| 768 RelocInfo::CODE_TARGET); | 801 RelocInfo::CODE_TARGET); |
| 769 } | 802 } |
| 803 |
| 804 __ bind(&stack_overflow); |
| 805 { |
| 806 // Pop the temporary registers, so that return address is on top of stack. |
| 807 __ Pop(edi); |
| 808 |
| 809 __ TailCallRuntime(Runtime::kThrowStackOverflow); |
| 810 |
| 811 // This should be unreachable. |
| 812 __ int3(); |
| 813 } |
| 770 } | 814 } |
| 771 | 815 |
| 772 namespace { | 816 namespace { |
| 773 | 817 |
| 774 // This function modified start_addr, and only reads the contents of num_args | 818 // This function modified start_addr, and only reads the contents of num_args |
| 775 // register. scratch1 and scratch2 are used as temporary registers. Their | 819 // register. scratch1 and scratch2 are used as temporary registers. Their |
| 776 // original values are restored after the use. | 820 // original values are restored after the use. |
| 777 void Generate_InterpreterPushArgsAndReturnAddress( | 821 void Generate_InterpreterPushArgsAndReturnAddress( |
| 778 MacroAssembler* masm, Register num_args, Register start_addr, | 822 MacroAssembler* masm, Register num_args, Register start_addr, |
| 779 Register scratch1, Register scratch2, bool receiver_in_args) { | 823 Register scratch1, Register scratch2, bool receiver_in_args, |
| 780 // Store scratch2, scratch1 onto the stack. We need to restore the original | 824 int num_slots_above_ret_addr, Label* stack_overflow) { |
| 781 // values | 825 // We have to move return address and the temporary registers above it |
| 782 // so store scratch2, scratch1 temporarily on stack. | 826 // before we can copy arguments onto the stack. To achieve this: |
| 783 __ Push(scratch2); | 827 // Step 1: Increment the stack pointer by num_args + 1 (for receiver). |
| 784 __ Push(scratch1); | 828 // Step 2: Move the return address and values above it to the top of stack. |
| 785 | 829 // Step 3: Copy the arguments into the correct locations. |
| 786 // We have to pop return address and the two temporary registers before we | |
| 787 // can push arguments onto the stack. we do not have any free registers so | |
| 788 // update the stack and copy them into the correct places on the stack. | |
| 789 // current stack =====> required stack layout | 830 // current stack =====> required stack layout |
| 790 // | | | scratch1 | (2) <-- esp(1) | 831 // | | | scratch1 | (2) <-- esp(1) |
| 791 // | | | scratch2 | (3) | 832 // | | | .... | (2) |
| 792 // | | | return addr | (4) | 833 // | | | scratch-n | (2) |
| 793 // | | | arg N | (5) | 834 // | | | return addr | (2) |
| 835 // | | | arg N | (3) |
| 794 // | scratch1 | <-- esp | .... | | 836 // | scratch1 | <-- esp | .... | |
| 795 // | scratch2 | | arg 0 | | 837 // | .... | | arg 0 | |
| 838 // | scratch-n | | arg 0 | |
| 796 // | return addr | | receiver slot | | 839 // | return addr | | receiver slot | |
| 797 | 840 |
| 798 // First increment the stack pointer to the correct location. | 841 // Check for stack overflow before we increment the stack pointer. |
| 799 // we need additional slots for arguments and the receiver. | 842 Generate_StackOverflowCheck(masm, num_args, scratch1, scratch2, |
| 800 // Step 1 - compute the required increment to the stack. | 843 stack_overflow, true); |
| 801 __ mov(scratch1, num_args); | 844 |
| 802 __ shl(scratch1, kPointerSizeLog2); | 845 // Step 1 - Update the stack pointer. scratch1 already contains the required |
| 803 __ add(scratch1, Immediate(kPointerSize)); | 846 // increment to the stack. i.e. num_args + 1 stack slots. This is computed in |
| 847 // the Generate_StackOverflowCheck. |
| 804 | 848 |
| 805 #ifdef _MSC_VER | 849 #ifdef _MSC_VER |
| 806 // TODO(mythria): Move it to macro assembler. | 850 // TODO(mythria): Move it to macro assembler. |
| 807 // In windows, we cannot increment the stack size by more than one page | 851 // In windows, we cannot increment the stack size by more than one page |
| 808 // (mimimum page size is 4KB) without accessing at least one byte on the | 852 // (mimimum page size is 4KB) without accessing at least one byte on the |
| 809 // page. Check this: | 853 // page. Check this: |
| 810 // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. | 854 // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. |
| 811 const int page_size = 4 * 1024; | 855 const int page_size = 4 * 1024; |
| 812 Label check_offset, update_stack_pointer; | 856 Label check_offset, update_stack_pointer; |
| 813 __ bind(&check_offset); | 857 __ bind(&check_offset); |
| 814 __ cmp(scratch1, page_size); | 858 __ cmp(scratch1, page_size); |
| 815 __ j(less, &update_stack_pointer); | 859 __ j(less, &update_stack_pointer); |
| 816 __ sub(esp, Immediate(page_size)); | 860 __ sub(esp, Immediate(page_size)); |
| 817 // Just to touch the page, before we increment further. | 861 // Just to touch the page, before we increment further. |
| 818 __ mov(Operand(esp, 0), Immediate(0)); | 862 __ mov(Operand(esp, 0), Immediate(0)); |
| 819 __ sub(scratch1, Immediate(page_size)); | 863 __ sub(scratch1, Immediate(page_size)); |
| 820 __ jmp(&check_offset); | 864 __ jmp(&check_offset); |
| 821 __ bind(&update_stack_pointer); | 865 __ bind(&update_stack_pointer); |
| 822 #endif | 866 #endif |
| 823 | 867 |
| 824 // TODO(mythria): Add a stack check before updating the stack pointer. | |
| 825 | |
| 826 // Step 1 - Update the stack pointer. | |
| 827 __ sub(esp, scratch1); | 868 __ sub(esp, scratch1); |
| 828 | 869 |
| 829 // Step 2 move scratch1 to the correct location. Move scratch1 first otherwise | 870 // Step 2 move return_address and slots above it to the correct locations. |
| 830 // we may overwrite when num_args = 0 or 1, basically when the source and | 871 // Move from top to bottom, otherwise we may overwrite when num_args = 0 or 1, |
| 831 // destination overlap. We at least need one extra slot for receiver, | 872 // basically when the source and destination overlap. We at least need one |
| 832 // so no extra checks are required to avoid copy. | 873 // extra slot for receiver, so no extra checks are required to avoid copy. |
| 833 __ mov(scratch1, | 874 for (int i = 0; i < num_slots_above_ret_addr + 1; i++) { |
| 834 Operand(esp, num_args, times_pointer_size, 1 * kPointerSize)); | 875 __ mov(scratch1, |
| 835 __ mov(Operand(esp, 0), scratch1); | 876 Operand(esp, num_args, times_pointer_size, (i + 1) * kPointerSize)); |
| 877 __ mov(Operand(esp, i * kPointerSize), scratch1); |
| 878 } |
| 836 | 879 |
| 837 // Step 3 move scratch2 to the correct location | 880 // Step 3 copy arguments to correct locations. |
| 838 __ mov(scratch1, | |
| 839 Operand(esp, num_args, times_pointer_size, 2 * kPointerSize)); | |
| 840 __ mov(Operand(esp, 1 * kPointerSize), scratch1); | |
| 841 | |
| 842 // Step 4 move return address to the correct location | |
| 843 __ mov(scratch1, | |
| 844 Operand(esp, num_args, times_pointer_size, 3 * kPointerSize)); | |
| 845 __ mov(Operand(esp, 2 * kPointerSize), scratch1); | |
| 846 | |
| 847 // Step 5 copy arguments to correct locations. | |
| 848 if (receiver_in_args) { | 881 if (receiver_in_args) { |
| 849 __ mov(scratch1, num_args); | 882 __ mov(scratch1, num_args); |
| 850 __ add(scratch1, Immediate(1)); | 883 __ add(scratch1, Immediate(1)); |
| 851 } else { | 884 } else { |
| 852 // Slot meant for receiver contains return address. Reset it so that | 885 // Slot meant for receiver contains return address. Reset it so that |
| 853 // we will not incorrectly interpret return address as an object. | 886 // we will not incorrectly interpret return address as an object. |
| 854 __ mov(Operand(esp, num_args, times_pointer_size, 3 * kPointerSize), | 887 __ mov(Operand(esp, num_args, times_pointer_size, |
| 888 (num_slots_above_ret_addr + 1) * kPointerSize), |
| 855 Immediate(0)); | 889 Immediate(0)); |
| 856 __ mov(scratch1, num_args); | 890 __ mov(scratch1, num_args); |
| 857 } | 891 } |
| 858 | 892 |
| 859 Label loop_header, loop_check; | 893 Label loop_header, loop_check; |
| 860 __ jmp(&loop_check); | 894 __ jmp(&loop_check); |
| 861 __ bind(&loop_header); | 895 __ bind(&loop_header); |
| 862 __ mov(scratch2, Operand(start_addr, 0)); | 896 __ mov(scratch2, Operand(start_addr, 0)); |
| 863 __ mov(Operand(esp, scratch1, times_pointer_size, 2 * kPointerSize), | 897 __ mov(Operand(esp, scratch1, times_pointer_size, |
| 898 num_slots_above_ret_addr * kPointerSize), |
| 864 scratch2); | 899 scratch2); |
| 865 __ sub(start_addr, Immediate(kPointerSize)); | 900 __ sub(start_addr, Immediate(kPointerSize)); |
| 866 __ sub(scratch1, Immediate(1)); | 901 __ sub(scratch1, Immediate(1)); |
| 867 __ bind(&loop_check); | 902 __ bind(&loop_check); |
| 868 __ cmp(scratch1, Immediate(0)); | 903 __ cmp(scratch1, Immediate(0)); |
| 869 __ j(greater, &loop_header, Label::kNear); | 904 __ j(greater, &loop_header, Label::kNear); |
| 870 | |
| 871 // Restore scratch1 and scratch2. | |
| 872 __ Pop(scratch1); | |
| 873 __ Pop(scratch2); | |
| 874 } | 905 } |
| 875 | 906 |
| 876 } // end anonymous namespace | 907 } // end anonymous namespace |
| 877 | 908 |
| 878 // static | 909 // static |
| 879 void Builtins::Generate_InterpreterPushArgsAndConstructImpl( | 910 void Builtins::Generate_InterpreterPushArgsAndConstructImpl( |
| 880 MacroAssembler* masm, CallableType construct_type) { | 911 MacroAssembler* masm, CallableType construct_type) { |
| 881 // ----------- S t a t e ------------- | 912 // ----------- S t a t e ------------- |
| 882 // -- eax : the number of arguments (not including the receiver) | 913 // -- eax : the number of arguments (not including the receiver) |
| 883 // -- edx : the new target | 914 // -- edx : the new target |
| 884 // -- edi : the constructor | 915 // -- edi : the constructor |
| 885 // -- ebx : allocation site feedback (if available or undefined) | 916 // -- ebx : allocation site feedback (if available or undefined) |
| 886 // -- ecx : the address of the first argument to be pushed. Subsequent | 917 // -- ecx : the address of the first argument to be pushed. Subsequent |
| 887 // arguments should be consecutive above this, in the same order as | 918 // arguments should be consecutive above this, in the same order as |
| 888 // they are to be pushed onto the stack. | 919 // they are to be pushed onto the stack. |
| 889 // ----------------------------------- | 920 // ----------------------------------- |
| 921 Label stack_overflow; |
| 922 // We need two scratch registers. Push edi and edx onto stack. |
| 923 __ Push(edi); |
| 924 __ Push(edx); |
| 890 | 925 |
| 891 // Push arguments and move return address to the top of stack. | 926 // Push arguments and move return address to the top of stack. |
| 892 // The eax register is readonly. The ecx register will be modified. The edx | 927 // The eax register is readonly. The ecx register will be modified. The edx |
| 893 // and edi registers will be modified but restored to their original values. | 928 // and edi registers will be modified but restored to their original values. |
| 894 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false); | 929 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false, |
| 930 2, &stack_overflow); |
| 931 |
| 932 // Restore edi and edx |
| 933 __ Pop(edx); |
| 934 __ Pop(edi); |
| 895 | 935 |
| 896 __ AssertUndefinedOrAllocationSite(ebx); | 936 __ AssertUndefinedOrAllocationSite(ebx); |
| 897 if (construct_type == CallableType::kJSFunction) { | 937 if (construct_type == CallableType::kJSFunction) { |
| 898 // Tail call to the function-specific construct stub (still in the caller | 938 // Tail call to the function-specific construct stub (still in the caller |
| 899 // context at this point). | 939 // context at this point). |
| 900 __ AssertFunction(edi); | 940 __ AssertFunction(edi); |
| 901 | 941 |
| 902 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 942 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 903 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); | 943 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); |
| 904 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); | 944 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); |
| 905 __ jmp(ecx); | 945 __ jmp(ecx); |
| 906 } else { | 946 } else { |
| 907 DCHECK_EQ(construct_type, CallableType::kAny); | 947 DCHECK_EQ(construct_type, CallableType::kAny); |
| 908 | 948 |
| 909 // Call the constructor with unmodified eax, edi, edx values. | 949 // Call the constructor with unmodified eax, edi, edx values. |
| 910 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 950 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
| 911 } | 951 } |
| 952 |
| 953 __ bind(&stack_overflow); |
| 954 { |
| 955 // Pop the temporary registers, so that return address is on top of stack. |
| 956 __ Pop(edx); |
| 957 __ Pop(edi); |
| 958 |
| 959 __ TailCallRuntime(Runtime::kThrowStackOverflow); |
| 960 |
| 961 // This should be unreachable. |
| 962 __ int3(); |
| 963 } |
| 912 } | 964 } |
| 913 | 965 |
| 914 // static | 966 // static |
| 915 void Builtins::Generate_InterpreterPushArgsAndConstructArray( | 967 void Builtins::Generate_InterpreterPushArgsAndConstructArray( |
| 916 MacroAssembler* masm) { | 968 MacroAssembler* masm) { |
| 917 // ----------- S t a t e ------------- | 969 // ----------- S t a t e ------------- |
| 918 // -- eax : the number of arguments (not including the receiver) | 970 // -- eax : the number of arguments (not including the receiver) |
| 919 // -- edx : the target to call checked to be Array function. | 971 // -- edx : the target to call checked to be Array function. |
| 920 // -- ebx : the allocation site feedback | 972 // -- ebx : the allocation site feedback |
| 921 // -- ecx : the address of the first argument to be pushed. Subsequent | 973 // -- ecx : the address of the first argument to be pushed. Subsequent |
| 922 // arguments should be consecutive above this, in the same order as | 974 // arguments should be consecutive above this, in the same order as |
| 923 // they are to be pushed onto the stack. | 975 // they are to be pushed onto the stack. |
| 924 // ----------------------------------- | 976 // ----------------------------------- |
| 977 Label stack_overflow; |
| 978 // We need two scratch registers. Register edi is available, push edx onto |
| 979 // stack. |
| 980 __ Push(edx); |
| 925 | 981 |
| 926 // Push arguments and move return address to the top of stack. | 982 // Push arguments and move return address to the top of stack. |
| 927 // The eax register is readonly. The ecx register will be modified. The edx | 983 // The eax register is readonly. The ecx register will be modified. The edx |
| 928 // and edi registers will be modified but restored to their original values. | 984 // and edi registers will be modified but restored to their original values. |
| 929 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, ebx, true); | 985 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, true, |
| 986 1, &stack_overflow); |
| 987 |
| 988 // Restore edx. |
| 989 __ Pop(edx); |
| 930 | 990 |
| 931 // Array constructor expects constructor in edi. It is same as edx here. | 991 // Array constructor expects constructor in edi. It is same as edx here. |
| 932 __ Move(edi, edx); | 992 __ Move(edi, edx); |
| 933 | 993 |
| 934 ArrayConstructorStub stub(masm->isolate()); | 994 ArrayConstructorStub stub(masm->isolate()); |
| 935 __ TailCallStub(&stub); | 995 __ TailCallStub(&stub); |
| 996 |
| 997 __ bind(&stack_overflow); |
| 998 { |
| 999 // Pop the temporary registers, so that return address is on top of stack. |
| 1000 __ Pop(edx); |
| 1001 |
| 1002 __ TailCallRuntime(Runtime::kThrowStackOverflow); |
| 1003 |
| 1004 // This should be unreachable. |
| 1005 __ int3(); |
| 1006 } |
| 936 } | 1007 } |
| 937 | 1008 |
| 938 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { | 1009 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { |
| 939 // Set the return address to the correct point in the interpreter entry | 1010 // Set the return address to the correct point in the interpreter entry |
| 940 // trampoline. | 1011 // trampoline. |
| 941 Smi* interpreter_entry_return_pc_offset( | 1012 Smi* interpreter_entry_return_pc_offset( |
| 942 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); | 1013 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); |
| 943 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); | 1014 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); |
| 944 __ LoadHeapObject(ebx, | 1015 __ LoadHeapObject(ebx, |
| 945 masm->isolate()->builtins()->InterpreterEntryTrampoline()); | 1016 masm->isolate()->builtins()->InterpreterEntryTrampoline()); |
| (...skipping 1156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2102 __ bind(&drop_frame_and_ret); | 2173 __ bind(&drop_frame_and_ret); |
| 2103 { | 2174 { |
| 2104 // Drop all arguments including the receiver. | 2175 // Drop all arguments including the receiver. |
| 2105 __ PopReturnAddressTo(ecx); | 2176 __ PopReturnAddressTo(ecx); |
| 2106 __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); | 2177 __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); |
| 2107 __ PushReturnAddressFrom(ecx); | 2178 __ PushReturnAddressFrom(ecx); |
| 2108 __ Ret(); | 2179 __ Ret(); |
| 2109 } | 2180 } |
| 2110 } | 2181 } |
| 2111 | 2182 |
| 2112 static void ArgumentsAdaptorStackCheck(MacroAssembler* masm, | |
| 2113 Label* stack_overflow) { | |
| 2114 // ----------- S t a t e ------------- | |
| 2115 // -- eax : actual number of arguments | |
| 2116 // -- ebx : expected number of arguments | |
| 2117 // -- edx : new target (passed through to callee) | |
| 2118 // ----------------------------------- | |
| 2119 // Check the stack for overflow. We are not trying to catch | |
| 2120 // interruptions (e.g. debug break and preemption) here, so the "real stack | |
| 2121 // limit" is checked. | |
| 2122 ExternalReference real_stack_limit = | |
| 2123 ExternalReference::address_of_real_stack_limit(masm->isolate()); | |
| 2124 __ mov(edi, Operand::StaticVariable(real_stack_limit)); | |
| 2125 // Make ecx the space we have left. The stack might already be overflowed | |
| 2126 // here which will cause ecx to become negative. | |
| 2127 __ mov(ecx, esp); | |
| 2128 __ sub(ecx, edi); | |
| 2129 // Make edi the space we need for the array when it is unrolled onto the | |
| 2130 // stack. | |
| 2131 __ mov(edi, ebx); | |
| 2132 __ shl(edi, kPointerSizeLog2); | |
| 2133 // Check if the arguments will overflow the stack. | |
| 2134 __ cmp(ecx, edi); | |
| 2135 __ j(less_equal, stack_overflow); // Signed comparison. | |
| 2136 } | |
| 2137 | |
| 2138 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { | 2183 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { |
| 2139 __ push(ebp); | 2184 __ push(ebp); |
| 2140 __ mov(ebp, esp); | 2185 __ mov(ebp, esp); |
| 2141 | 2186 |
| 2142 // Store the arguments adaptor context sentinel. | 2187 // Store the arguments adaptor context sentinel. |
| 2143 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2188 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2144 | 2189 |
| 2145 // Push the function on the stack. | 2190 // Push the function on the stack. |
| 2146 __ push(edi); | 2191 __ push(edi); |
| 2147 | 2192 |
| (...skipping 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2863 | 2908 |
| 2864 Label enough, too_few; | 2909 Label enough, too_few; |
| 2865 __ cmp(eax, ebx); | 2910 __ cmp(eax, ebx); |
| 2866 __ j(less, &too_few); | 2911 __ j(less, &too_few); |
| 2867 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); | 2912 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
| 2868 __ j(equal, &dont_adapt_arguments); | 2913 __ j(equal, &dont_adapt_arguments); |
| 2869 | 2914 |
| 2870 { // Enough parameters: Actual >= expected. | 2915 { // Enough parameters: Actual >= expected. |
| 2871 __ bind(&enough); | 2916 __ bind(&enough); |
| 2872 EnterArgumentsAdaptorFrame(masm); | 2917 EnterArgumentsAdaptorFrame(masm); |
| 2873 ArgumentsAdaptorStackCheck(masm, &stack_overflow); | 2918 // edi is used as a scratch register. It should be restored from the frame |
| 2919 // when needed. |
| 2920 Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); |
| 2874 | 2921 |
| 2875 // Copy receiver and all expected arguments. | 2922 // Copy receiver and all expected arguments. |
| 2876 const int offset = StandardFrameConstants::kCallerSPOffset; | 2923 const int offset = StandardFrameConstants::kCallerSPOffset; |
| 2877 __ lea(edi, Operand(ebp, eax, times_4, offset)); | 2924 __ lea(edi, Operand(ebp, eax, times_4, offset)); |
| 2878 __ mov(eax, -1); // account for receiver | 2925 __ mov(eax, -1); // account for receiver |
| 2879 | 2926 |
| 2880 Label copy; | 2927 Label copy; |
| 2881 __ bind(©); | 2928 __ bind(©); |
| 2882 __ inc(eax); | 2929 __ inc(eax); |
| 2883 __ push(Operand(edi, 0)); | 2930 __ push(Operand(edi, 0)); |
| 2884 __ sub(edi, Immediate(kPointerSize)); | 2931 __ sub(edi, Immediate(kPointerSize)); |
| 2885 __ cmp(eax, ebx); | 2932 __ cmp(eax, ebx); |
| 2886 __ j(less, ©); | 2933 __ j(less, ©); |
| 2887 // eax now contains the expected number of arguments. | 2934 // eax now contains the expected number of arguments. |
| 2888 __ jmp(&invoke); | 2935 __ jmp(&invoke); |
| 2889 } | 2936 } |
| 2890 | 2937 |
| 2891 { // Too few parameters: Actual < expected. | 2938 { // Too few parameters: Actual < expected. |
| 2892 __ bind(&too_few); | 2939 __ bind(&too_few); |
| 2893 | |
| 2894 EnterArgumentsAdaptorFrame(masm); | 2940 EnterArgumentsAdaptorFrame(masm); |
| 2895 ArgumentsAdaptorStackCheck(masm, &stack_overflow); | 2941 // edi is used as a scratch register. It should be restored from the frame |
| 2942 // when needed. |
| 2943 Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); |
| 2896 | 2944 |
| 2897 // Remember expected arguments in ecx. | 2945 // Remember expected arguments in ecx. |
| 2898 __ mov(ecx, ebx); | 2946 __ mov(ecx, ebx); |
| 2899 | 2947 |
| 2900 // Copy receiver and all actual arguments. | 2948 // Copy receiver and all actual arguments. |
| 2901 const int offset = StandardFrameConstants::kCallerSPOffset; | 2949 const int offset = StandardFrameConstants::kCallerSPOffset; |
| 2902 __ lea(edi, Operand(ebp, eax, times_4, offset)); | 2950 __ lea(edi, Operand(ebp, eax, times_4, offset)); |
| 2903 // ebx = expected - actual. | 2951 // ebx = expected - actual. |
| 2904 __ sub(ebx, eax); | 2952 __ sub(ebx, eax); |
| 2905 // eax = -actual - 1 | 2953 // eax = -actual - 1 |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3120 | 3168 |
| 3121 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { | 3169 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { |
| 3122 Generate_OnStackReplacementHelper(masm, true); | 3170 Generate_OnStackReplacementHelper(masm, true); |
| 3123 } | 3171 } |
| 3124 | 3172 |
| 3125 #undef __ | 3173 #undef __ |
| 3126 } // namespace internal | 3174 } // namespace internal |
| 3127 } // namespace v8 | 3175 } // namespace v8 |
| 3128 | 3176 |
| 3129 #endif // V8_TARGET_ARCH_X87 | 3177 #endif // V8_TARGET_ARCH_X87 |
| OLD | NEW |