Chromium Code Reviews| 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 // Check the stack for overflow. We are not trying to catch | |
| 710 // interruptions (e.g. debug break and preemption) here, so the "real stack | |
| 711 // limit" is checked. | |
| 712 ExternalReference real_stack_limit = | |
| 713 ExternalReference::address_of_real_stack_limit(masm->isolate()); | |
| 714 __ mov(scratch1, Operand::StaticVariable(real_stack_limit)); | |
| 715 // Make scratch2 the space we have left. The stack might already be overflowed | |
| 716 // here which will cause scratch2 to become negative. | |
| 717 __ mov(scratch2, esp); | |
| 718 __ sub(scratch2, scratch1); | |
| 719 // Make scratch1 the space we need for the array when it is unrolled onto the | |
| 720 // stack. | |
| 721 __ mov(scratch1, num_args); | |
| 722 __ shl(scratch1, kPointerSizeLog2); | |
| 723 // Check if the arguments will overflow the stack. | |
| 724 __ cmp(scratch2, scratch1); | |
| 725 __ j(less_equal, stack_overflow); // Signed comparison. | |
| 726 } | |
| 727 | |
| 706 static void Generate_InterpreterPushArgs(MacroAssembler* masm, | 728 static void Generate_InterpreterPushArgs(MacroAssembler* masm, |
| 707 Register array_limit, | 729 Register array_limit, |
| 708 Register start_address) { | 730 Register start_address) { |
| 709 // ----------- S t a t e ------------- | 731 // ----------- S t a t e ------------- |
| 710 // -- start_address : Pointer to the last argument in the args array. | 732 // -- start_address : Pointer to the last argument in the args array. |
| 711 // -- array_limit : Pointer to one before the first argument in the | 733 // -- array_limit : Pointer to one before the first argument in the |
| 712 // args array. | 734 // args array. |
| 713 // ----------------------------------- | 735 // ----------------------------------- |
| 714 Label loop_header, loop_check; | 736 Label loop_header, loop_check; |
| 715 __ jmp(&loop_check); | 737 __ jmp(&loop_check); |
| 716 __ bind(&loop_header); | 738 __ bind(&loop_header); |
| 717 __ Push(Operand(start_address, 0)); | 739 __ Push(Operand(start_address, 0)); |
| 718 __ sub(start_address, Immediate(kPointerSize)); | 740 __ sub(start_address, Immediate(kPointerSize)); |
| 719 __ bind(&loop_check); | 741 __ bind(&loop_check); |
| 720 __ cmp(start_address, array_limit); | 742 __ cmp(start_address, array_limit); |
| 721 __ j(greater, &loop_header, Label::kNear); | 743 __ j(greater, &loop_header, Label::kNear); |
| 722 } | 744 } |
| 723 | 745 |
| 724 // static | 746 // static |
| 725 void Builtins::Generate_InterpreterPushArgsAndCallImpl( | 747 void Builtins::Generate_InterpreterPushArgsAndCallImpl( |
| 726 MacroAssembler* masm, TailCallMode tail_call_mode, | 748 MacroAssembler* masm, TailCallMode tail_call_mode, |
| 727 CallableType function_type) { | 749 CallableType function_type) { |
| 728 // ----------- S t a t e ------------- | 750 // ----------- S t a t e ------------- |
| 729 // -- eax : the number of arguments (not including the receiver) | 751 // -- eax : the number of arguments (not including the receiver) |
| 730 // -- ebx : the address of the first argument to be pushed. Subsequent | 752 // -- ebx : the address of the first argument to be pushed. Subsequent |
| 731 // arguments should be consecutive above this, in the same order as | 753 // arguments should be consecutive above this, in the same order as |
| 732 // they are to be pushed onto the stack. | 754 // they are to be pushed onto the stack. |
| 733 // -- edi : the target to call (can be any Object). | 755 // -- edi : the target to call (can be any Object). |
| 734 // ----------------------------------- | 756 // ----------------------------------- |
| 757 Label stack_overflow; | |
| 758 // Compute the expected number of arguments. | |
| 759 __ mov(ecx, eax); | |
| 760 __ add(ecx, Immediate(1)); // Add one for receiver. | |
| 761 | |
| 762 // Add a stack check before pushing the arguments. We need an extra register | |
| 763 // to perform a stack check. So push it onto the stack temporarily. This | |
| 764 // might cause stack overflow, but it will be detected by the check. | |
| 765 __ Push(edi); | |
| 766 Generate_StackOverflowCheck(masm, ecx, edx, edi, &stack_overflow); | |
| 767 __ Pop(edi); | |
| 735 | 768 |
| 736 // Pop return address to allow tail-call after pushing arguments. | 769 // Pop return address to allow tail-call after pushing arguments. |
| 737 __ Pop(edx); | 770 __ Pop(edx); |
| 738 | 771 |
| 739 // Find the address of the last argument. | 772 // Find the address of the last argument. |
| 740 __ mov(ecx, eax); | |
| 741 __ add(ecx, Immediate(1)); // Add one for receiver. | |
| 742 __ shl(ecx, kPointerSizeLog2); | 773 __ shl(ecx, kPointerSizeLog2); |
| 743 __ neg(ecx); | 774 __ neg(ecx); |
| 744 __ add(ecx, ebx); | 775 __ add(ecx, ebx); |
| 745 | |
| 746 // TODO(mythria): Add a stack check before pushing the arguments. | |
| 747 Generate_InterpreterPushArgs(masm, ecx, ebx); | 776 Generate_InterpreterPushArgs(masm, ecx, ebx); |
| 748 | 777 |
| 749 // Call the target. | 778 // Call the target. |
| 750 __ Push(edx); // Re-push return address. | 779 __ Push(edx); // Re-push return address. |
| 751 | 780 |
| 752 if (function_type == CallableType::kJSFunction) { | 781 if (function_type == CallableType::kJSFunction) { |
| 753 __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, | 782 __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, |
| 754 tail_call_mode), | 783 tail_call_mode), |
| 755 RelocInfo::CODE_TARGET); | 784 RelocInfo::CODE_TARGET); |
| 756 } else { | 785 } else { |
| 757 DCHECK_EQ(function_type, CallableType::kAny); | 786 DCHECK_EQ(function_type, CallableType::kAny); |
| 758 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, | 787 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, |
| 759 tail_call_mode), | 788 tail_call_mode), |
| 760 RelocInfo::CODE_TARGET); | 789 RelocInfo::CODE_TARGET); |
| 761 } | 790 } |
| 791 | |
| 792 __ bind(&stack_overflow); | |
| 793 { | |
| 794 // Pop the temporary registers, so that return address is on top of stack. | |
| 795 __ Pop(edi); | |
| 796 | |
| 797 __ TailCallRuntime(Runtime::kThrowStackOverflow); | |
| 798 | |
| 799 // This should be unreachable. | |
| 800 __ int3(); | |
| 801 } | |
| 762 } | 802 } |
| 763 | 803 |
| 764 namespace { | 804 namespace { |
| 765 | 805 |
| 766 // This function modified start_addr, and only reads the contents of num_args | 806 void Generate_InterpreterPushArgsUpdateStackPointer(MacroAssembler* masm, |
| 767 // register. scratch1 and scratch2 are used as temporary registers. Their | 807 Register num_args, |
| 768 // original values are restored after the use. | 808 Register scratch1, |
| 769 void Generate_InterpreterPushArgsAndReturnAddress( | 809 Register scratch2, |
| 770 MacroAssembler* masm, Register num_args, Register start_addr, | 810 Label* stack_overflow) { |
| 771 Register scratch1, Register scratch2, bool receiver_in_args) { | 811 // Check for stack overflow. We are not trying to catch interrupts (e.g. |
| 772 // Store scratch2, scratch1 onto the stack. We need to restore the original | 812 // debug break and preemption) here, so the "real stack limit" is checked. |
| 773 // values | 813 ExternalReference real_stack_limit = |
| 774 // so store scratch2, scratch1 temporarily on stack. | 814 ExternalReference::address_of_real_stack_limit(masm->isolate()); |
| 775 __ Push(scratch2); | 815 __ mov(scratch1, Operand::StaticVariable(real_stack_limit)); |
| 776 __ Push(scratch1); | 816 // Make scratch2 the space we have left. The stack might already be overflowed |
| 817 // here which will cause scratch2 to become negative. | |
| 818 __ mov(scratch2, esp); | |
| 819 __ sub(scratch2, scratch1); | |
| 777 | 820 |
| 778 // We have to pop return address and the two temporary registers before we | 821 // Compute expected number of arguments. |
| 779 // can push arguments onto the stack. we do not have any free registers so | 822 __ mov(scratch1, num_args); |
| 780 // update the stack and copy them into the correct places on the stack. | 823 __ add(scratch1, Immediate(1)); // Add one for receiver. |
| 781 // current stack =====> required stack layout | 824 __ shl(scratch1, kPointerSizeLog2); |
| 782 // | | | scratch1 | (2) <-- esp(1) | |
| 783 // | | | scratch2 | (3) | |
| 784 // | | | return addr | (4) | |
| 785 // | | | arg N | (5) | |
| 786 // | scratch1 | <-- esp | .... | | |
| 787 // | scratch2 | | arg 0 | | |
| 788 // | return addr | | receiver slot | | |
| 789 | 825 |
| 790 // First increment the stack pointer to the correct location. | 826 __ cmp(scratch2, scratch1); |
| 791 // we need additional slots for arguments and the receiver. | 827 __ j(less_equal, stack_overflow); // Signed comparison. |
| 792 // Step 1 - compute the required increment to the stack. | |
| 793 __ mov(scratch1, num_args); | |
| 794 __ shl(scratch1, kPointerSizeLog2); | |
| 795 __ add(scratch1, Immediate(kPointerSize)); | |
| 796 | 828 |
| 829 // Update the stack pointer to the correct location. | |
| 797 #ifdef _MSC_VER | 830 #ifdef _MSC_VER |
| 798 // TODO(mythria): Move it to macro assembler. | 831 // TODO(mythria): Move it to macro assembler. |
| 799 // In windows, we cannot increment the stack size by more than one page | 832 // 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 | 833 // (mimimum page size is 4KB) without accessing at least one byte on the |
| 801 // page. Check this: | 834 // page. Check this: |
| 802 // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. | 835 // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. |
| 803 const int page_size = 4 * 1024; | 836 const int page_size = 4 * 1024; |
| 804 Label check_offset, update_stack_pointer; | 837 Label check_offset, update_stack_pointer; |
| 805 __ bind(&check_offset); | 838 __ bind(&check_offset); |
| 806 __ cmp(scratch1, page_size); | 839 __ cmp(scratch1, page_size); |
| 807 __ j(less, &update_stack_pointer); | 840 __ j(less, &update_stack_pointer); |
| 808 __ sub(esp, Immediate(page_size)); | 841 __ sub(esp, Immediate(page_size)); |
| 809 // Just to touch the page, before we increment further. | 842 // Just to touch the page, before we increment further. |
| 810 __ mov(Operand(esp, 0), Immediate(0)); | 843 __ mov(Operand(esp, 0), Immediate(0)); |
| 811 __ sub(scratch1, Immediate(page_size)); | 844 __ sub(scratch1, Immediate(page_size)); |
| 812 __ jmp(&check_offset); | 845 __ jmp(&check_offset); |
| 813 __ bind(&update_stack_pointer); | 846 __ bind(&update_stack_pointer); |
| 814 #endif | 847 #endif |
| 815 | 848 |
| 816 // TODO(mythria): Add a stack check before updating the stack pointer. | 849 __ sub(esp, scratch1); |
| 850 } | |
| 817 | 851 |
| 818 // Step 1 - Update the stack pointer. | 852 void Generate_InterpreterPushArgsMoveReturnAddress(MacroAssembler* masm, |
| 819 __ sub(esp, scratch1); | 853 Register num_args, |
| 854 Register scratch, | |
| 855 int num_slots_to_move) { | |
| 856 for (int i = 0; i < num_slots_to_move; i++) { | |
| 857 __ mov(scratch, | |
| 858 Operand(esp, num_args, times_pointer_size, (i + 1) * kPointerSize)); | |
| 859 __ mov(Operand(esp, i * kPointerSize), scratch); | |
| 860 } | |
| 861 } | |
| 820 | 862 |
| 821 // Step 2 move scratch1 to the correct location. Move scratch1 first otherwise | 863 void Generate_InterpreterPushArgsCopyArguments(MacroAssembler* masm, |
| 822 // we may overwrite when num_args = 0 or 1, basically when the source and | 864 Register start_addr, |
| 823 // destination overlap. We at least need one extra slot for receiver, | 865 Register array_limit, |
| 824 // so no extra checks are required to avoid copy. | 866 Register dest_addr, |
| 825 __ mov(scratch1, | 867 Register scratch) { |
| 826 Operand(esp, num_args, times_pointer_size, 1 * kPointerSize)); | |
| 827 __ mov(Operand(esp, 0), scratch1); | |
| 828 | |
| 829 // Step 3 move scratch2 to the correct location | |
| 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) { | |
| 841 __ mov(scratch1, num_args); | |
| 842 __ add(scratch1, Immediate(1)); | |
| 843 } else { | |
| 844 // Slot meant for receiver contains return address. Reset it so that | |
| 845 // we will not incorrectly interpret return address as an object. | |
| 846 __ mov(Operand(esp, num_args, times_pointer_size, 3 * kPointerSize), | |
| 847 Immediate(0)); | |
| 848 __ mov(scratch1, num_args); | |
| 849 } | |
| 850 | |
| 851 Label loop_header, loop_check; | 868 Label loop_header, loop_check; |
| 852 __ jmp(&loop_check); | 869 __ jmp(&loop_check); |
| 853 __ bind(&loop_header); | 870 __ bind(&loop_header); |
| 854 __ mov(scratch2, Operand(start_addr, 0)); | 871 __ mov(scratch, Operand(start_addr, 0)); |
| 855 __ mov(Operand(esp, scratch1, times_pointer_size, 2 * kPointerSize), | 872 __ mov(Operand(dest_addr, 0), scratch); |
| 856 scratch2); | |
| 857 __ sub(start_addr, Immediate(kPointerSize)); | 873 __ sub(start_addr, Immediate(kPointerSize)); |
| 858 __ sub(scratch1, Immediate(1)); | 874 __ sub(dest_addr, Immediate(kPointerSize)); |
| 859 __ bind(&loop_check); | 875 __ bind(&loop_check); |
| 860 __ cmp(scratch1, Immediate(0)); | 876 __ cmp(start_addr, array_limit); |
| 861 __ j(greater, &loop_header, Label::kNear); | 877 __ j(greater, &loop_header, Label::kNear); |
| 862 | |
| 863 // Restore scratch1 and scratch2. | |
| 864 __ Pop(scratch1); | |
| 865 __ Pop(scratch2); | |
| 866 } | 878 } |
| 867 | 879 |
| 868 } // end anonymous namespace | 880 } // end anonymous namespace |
| 869 | 881 |
| 870 // static | 882 // static |
| 871 void Builtins::Generate_InterpreterPushArgsAndConstructImpl( | 883 void Builtins::Generate_InterpreterPushArgsAndConstructImpl( |
| 872 MacroAssembler* masm, CallableType construct_type) { | 884 MacroAssembler* masm, CallableType construct_type) { |
| 873 // ----------- S t a t e ------------- | 885 // ----------- S t a t e ------------- |
| 874 // -- eax : the number of arguments (not including the receiver) | 886 // -- eax : the number of arguments (not including the receiver) |
| 875 // -- edx : the new target | 887 // -- edx : the new target |
| 876 // -- edi : the constructor | 888 // -- edi : the constructor |
| 877 // -- ebx : allocation site feedback (if available or undefined) | 889 // -- ebx : allocation site feedback (if available or undefined) |
| 878 // -- ecx : the address of the first argument to be pushed. Subsequent | 890 // -- ecx : the address of the first argument to be pushed. Subsequent |
| 879 // arguments should be consecutive above this, in the same order as | 891 // arguments should be consecutive above this, in the same order as |
| 880 // they are to be pushed onto the stack. | 892 // they are to be pushed onto the stack. |
| 881 // ----------------------------------- | 893 // ----------------------------------- |
| 894 Label stack_overflow; | |
| 895 int num_slots_above_ret_address = 3; | |
| 882 | 896 |
| 883 // Push arguments and move return address to the top of stack. | 897 // We need three scratch registers. Push edi, edx and ebx onto stack. |
| 884 // The eax register is readonly. The ecx register will be modified. The edx | 898 __ Push(edi); |
| 885 // and edi registers will be modified but restored to their original values. | 899 __ Push(edx); |
| 886 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false); | 900 __ Push(ebx); |
| 901 | |
| 902 // We have to pop return address and the two temporary registers before we | |
| 903 // can push arguments onto the stack. | |
| 904 // current stack =====> required stack layout | |
| 905 // | | | scratch3 | (2) <-- esp(1) | |
| 906 // | | | scratch2 | (2) | |
| 907 // | | | scratch1 | (2) | |
| 908 // | | | return addr | (2) | |
| 909 // | scratch3 | <-- esp | arg N | (3) | |
| 910 // | scratch2 | | .... | | |
| 911 // | scratch1 | | arg 0 | | |
| 912 // | return addr | | receiver slot | | |
| 913 | |
| 914 // Step1: Update the stack pointer to the correct location after verifying the | |
| 915 // stack does not overflow. | |
| 916 // The register eax is readonly, registers edi and edx are used as scratch. | |
| 917 Generate_InterpreterPushArgsUpdateStackPointer(masm, eax, edi, edx, | |
| 918 &stack_overflow); | |
| 919 | |
| 920 // Step2: Move return address and the two temporary registers to correct | |
| 921 // locations.This function will move return address and all the values above | |
| 922 // it by num_args + 1 locations. | |
| 923 // The register eax is readonly, register edx is used as scratch. | |
| 924 Generate_InterpreterPushArgsMoveReturnAddress( | |
| 925 masm, eax, edx, num_slots_above_ret_address + 1); | |
| 926 | |
| 927 // Slot meant for receiver contains return address. Reset it so that | |
| 928 // we will not incorrectly interpret return address as an object. | |
| 929 __ mov(Operand(esp, eax, times_pointer_size, | |
| 930 (num_slots_above_ret_address + 1) * kPointerSize), | |
| 931 Immediate(0)); | |
| 932 | |
| 933 // Copy the arguments. | |
| 934 // Find the address of the last argument. | |
| 935 __ mov(edx, eax); | |
| 936 __ shl(edx, kPointerSizeLog2); | |
| 937 __ neg(edx); | |
| 938 __ add(edx, ecx); | |
| 939 | |
| 940 // Find the destination address. | |
| 941 __ lea(edi, Operand(esp, eax, times_pointer_size, | |
| 942 (num_slots_above_ret_address)*kPointerSize)); | |
|
rmcilroy
2016/09/13 10:13:56
space between binary ops
mythria
2016/09/13 11:02:32
Done.
| |
| 943 | |
| 944 Generate_InterpreterPushArgsCopyArguments(masm, ecx, edx, edi, ebx); | |
| 945 | |
| 946 // Restore ebx, edx and edi. | |
| 947 __ Pop(ebx); | |
| 948 __ Pop(edx); | |
| 949 __ Pop(edi); | |
| 887 | 950 |
| 888 __ AssertUndefinedOrAllocationSite(ebx); | 951 __ AssertUndefinedOrAllocationSite(ebx); |
| 889 if (construct_type == CallableType::kJSFunction) { | 952 if (construct_type == CallableType::kJSFunction) { |
| 890 // Tail call to the function-specific construct stub (still in the caller | 953 // Tail call to the function-specific construct stub (still in the caller |
| 891 // context at this point). | 954 // context at this point). |
| 892 __ AssertFunction(edi); | 955 __ AssertFunction(edi); |
| 893 | 956 |
| 894 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 957 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 895 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); | 958 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); |
| 896 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); | 959 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); |
| 897 __ jmp(ecx); | 960 __ jmp(ecx); |
| 898 } else { | 961 } else { |
| 899 DCHECK_EQ(construct_type, CallableType::kAny); | 962 DCHECK_EQ(construct_type, CallableType::kAny); |
| 900 | 963 |
| 901 // Call the constructor with unmodified eax, edi, edx values. | 964 // Call the constructor with unmodified eax, edi, edx values. |
| 902 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 965 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
| 903 } | 966 } |
| 967 | |
| 968 __ bind(&stack_overflow); | |
| 969 { | |
| 970 // Pop the temporary registers, so that return address is on top of stack. | |
| 971 __ Pop(ebx); | |
| 972 __ Pop(edx); | |
| 973 __ Pop(edi); | |
| 974 | |
| 975 __ TailCallRuntime(Runtime::kThrowStackOverflow); | |
| 976 | |
| 977 // This should be unreachable. | |
| 978 __ int3(); | |
| 979 } | |
| 904 } | 980 } |
| 905 | 981 |
| 906 // static | 982 // static |
| 907 void Builtins::Generate_InterpreterPushArgsAndConstructArray( | 983 void Builtins::Generate_InterpreterPushArgsAndConstructArray( |
| 908 MacroAssembler* masm) { | 984 MacroAssembler* masm) { |
| 909 // ----------- S t a t e ------------- | 985 // ----------- S t a t e ------------- |
| 910 // -- eax : the number of arguments (not including the receiver) | 986 // -- eax : the number of arguments (not including the receiver) |
| 911 // -- edx : the target to call checked to be Array function. | 987 // -- edx : the target to call checked to be Array function. |
| 912 // -- ebx : the allocation site feedback | 988 // -- ebx : the allocation site feedback |
| 913 // -- ecx : the address of the first argument to be pushed. Subsequent | 989 // -- ecx : the address of the first argument to be pushed. Subsequent |
| 914 // arguments should be consecutive above this, in the same order as | 990 // arguments should be consecutive above this, in the same order as |
| 915 // they are to be pushed onto the stack. | 991 // they are to be pushed onto the stack. |
| 916 // ----------------------------------- | 992 // ----------------------------------- |
| 993 Label stack_overflow; | |
| 994 int num_slots_above_ret_address = 2; | |
| 917 | 995 |
| 918 // Push arguments and move return address to the top of stack. | 996 // We need three scratch registers. Push edx and ebx onto stack. The register |
| 919 // The eax register is readonly. The ecx register will be modified. The edx | 997 // edi is already available. |
| 920 // and edi registers will be modified but restored to their original values. | 998 __ Push(edx); |
| 921 Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, ebx, true); | 999 __ Push(ebx); |
| 1000 | |
| 1001 // Step1: Update the stack pointer to the correct location after verifying the | |
| 1002 // stack does not overflow. | |
| 1003 // The register eax is readonly, registers edi and edx are used as scratch. | |
| 1004 Generate_InterpreterPushArgsUpdateStackPointer(masm, eax, edi, edx, | |
| 1005 &stack_overflow); | |
| 1006 | |
| 1007 // Step2: Move return address and the two temporary registers to correct | |
| 1008 // locations. This function will move return address and all the values above | |
| 1009 // it by num_args + 1 locations. | |
| 1010 // The register eax is readonly, register edx is used as scratch. | |
| 1011 Generate_InterpreterPushArgsMoveReturnAddress( | |
| 1012 masm, eax, edx, num_slots_above_ret_address + 1); | |
| 1013 | |
| 1014 // Copy the arguments. | |
| 1015 // Find the address of the last argument. | |
| 1016 __ mov(edx, eax); | |
| 1017 __ add(edx, Immediate(1)); | |
| 1018 __ shl(edx, kPointerSizeLog2); | |
| 1019 __ neg(edx); | |
| 1020 __ add(edx, ecx); | |
| 1021 | |
| 1022 // Find the destination address. | |
| 1023 __ lea(edi, Operand(esp, eax, times_pointer_size, | |
| 1024 (num_slots_above_ret_address + 1) * kPointerSize)); | |
| 1025 | |
| 1026 Generate_InterpreterPushArgsCopyArguments(masm, ecx, edx, edi, ebx); | |
|
rmcilroy
2016/09/13 10:13:56
As discussed, could we merge these back into the h
mythria
2016/09/13 11:02:32
Done.
| |
| 1027 | |
| 1028 // Restore edx and edi. | |
| 1029 __ Pop(ebx); | |
| 1030 __ Pop(edx); | |
| 922 | 1031 |
| 923 // Array constructor expects constructor in edi. It is same as edx here. | 1032 // Array constructor expects constructor in edi. It is same as edx here. |
| 924 __ Move(edi, edx); | 1033 __ Move(edi, edx); |
| 925 | 1034 |
| 926 ArrayConstructorStub stub(masm->isolate()); | 1035 ArrayConstructorStub stub(masm->isolate()); |
| 927 __ TailCallStub(&stub); | 1036 __ TailCallStub(&stub); |
| 1037 | |
| 1038 __ bind(&stack_overflow); | |
| 1039 { | |
| 1040 // Pop the temporary registers, so that return address is on top of stack. | |
| 1041 __ Pop(ebx); | |
| 1042 __ Pop(edx); | |
| 1043 | |
| 1044 __ TailCallRuntime(Runtime::kThrowStackOverflow); | |
| 1045 | |
| 1046 // This should be unreachable. | |
| 1047 __ int3(); | |
| 1048 } | |
| 928 } | 1049 } |
| 929 | 1050 |
| 930 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { | 1051 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { |
| 931 // Set the return address to the correct point in the interpreter entry | 1052 // Set the return address to the correct point in the interpreter entry |
| 932 // trampoline. | 1053 // trampoline. |
| 933 Smi* interpreter_entry_return_pc_offset( | 1054 Smi* interpreter_entry_return_pc_offset( |
| 934 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); | 1055 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); |
| 935 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); | 1056 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); |
| 936 __ LoadHeapObject(ebx, | 1057 __ LoadHeapObject(ebx, |
| 937 masm->isolate()->builtins()->InterpreterEntryTrampoline()); | 1058 masm->isolate()->builtins()->InterpreterEntryTrampoline()); |
| (...skipping 1205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2143 __ bind(&drop_frame_and_ret); | 2264 __ bind(&drop_frame_and_ret); |
| 2144 { | 2265 { |
| 2145 // Drop all arguments including the receiver. | 2266 // Drop all arguments including the receiver. |
| 2146 __ PopReturnAddressTo(ecx); | 2267 __ PopReturnAddressTo(ecx); |
| 2147 __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); | 2268 __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); |
| 2148 __ PushReturnAddressFrom(ecx); | 2269 __ PushReturnAddressFrom(ecx); |
| 2149 __ Ret(); | 2270 __ Ret(); |
| 2150 } | 2271 } |
| 2151 } | 2272 } |
| 2152 | 2273 |
| 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) { | 2274 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { |
| 2180 __ push(ebp); | 2275 __ push(ebp); |
| 2181 __ mov(ebp, esp); | 2276 __ mov(ebp, esp); |
| 2182 | 2277 |
| 2183 // Store the arguments adaptor context sentinel. | 2278 // Store the arguments adaptor context sentinel. |
| 2184 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2279 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2185 | 2280 |
| 2186 // Push the function on the stack. | 2281 // Push the function on the stack. |
| 2187 __ push(edi); | 2282 __ push(edi); |
| 2188 | 2283 |
| (...skipping 726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2915 | 3010 |
| 2916 Label enough, too_few; | 3011 Label enough, too_few; |
| 2917 __ cmp(eax, ebx); | 3012 __ cmp(eax, ebx); |
| 2918 __ j(less, &too_few); | 3013 __ j(less, &too_few); |
| 2919 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); | 3014 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
| 2920 __ j(equal, &dont_adapt_arguments); | 3015 __ j(equal, &dont_adapt_arguments); |
| 2921 | 3016 |
| 2922 { // Enough parameters: Actual >= expected. | 3017 { // Enough parameters: Actual >= expected. |
| 2923 __ bind(&enough); | 3018 __ bind(&enough); |
| 2924 EnterArgumentsAdaptorFrame(masm); | 3019 EnterArgumentsAdaptorFrame(masm); |
| 2925 ArgumentsAdaptorStackCheck(masm, &stack_overflow); | 3020 // edi is used as a scratch register. It should be restored from the frame |
| 3021 // when needed. | |
| 3022 Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); | |
| 2926 | 3023 |
| 2927 // Copy receiver and all expected arguments. | 3024 // Copy receiver and all expected arguments. |
| 2928 const int offset = StandardFrameConstants::kCallerSPOffset; | 3025 const int offset = StandardFrameConstants::kCallerSPOffset; |
| 2929 __ lea(edi, Operand(ebp, eax, times_4, offset)); | 3026 __ lea(edi, Operand(ebp, eax, times_4, offset)); |
| 2930 __ mov(eax, -1); // account for receiver | 3027 __ mov(eax, -1); // account for receiver |
| 2931 | 3028 |
| 2932 Label copy; | 3029 Label copy; |
| 2933 __ bind(©); | 3030 __ bind(©); |
| 2934 __ inc(eax); | 3031 __ inc(eax); |
| 2935 __ push(Operand(edi, 0)); | 3032 __ push(Operand(edi, 0)); |
| 2936 __ sub(edi, Immediate(kPointerSize)); | 3033 __ sub(edi, Immediate(kPointerSize)); |
| 2937 __ cmp(eax, ebx); | 3034 __ cmp(eax, ebx); |
| 2938 __ j(less, ©); | 3035 __ j(less, ©); |
| 2939 // eax now contains the expected number of arguments. | 3036 // eax now contains the expected number of arguments. |
| 2940 __ jmp(&invoke); | 3037 __ jmp(&invoke); |
| 2941 } | 3038 } |
| 2942 | 3039 |
| 2943 { // Too few parameters: Actual < expected. | 3040 { // Too few parameters: Actual < expected. |
| 2944 __ bind(&too_few); | 3041 __ bind(&too_few); |
| 2945 EnterArgumentsAdaptorFrame(masm); | 3042 EnterArgumentsAdaptorFrame(masm); |
| 2946 ArgumentsAdaptorStackCheck(masm, &stack_overflow); | 3043 // edi is used as a scratch register. It should be restored from the frame |
| 3044 // when needed. | |
| 3045 Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); | |
| 2947 | 3046 |
| 2948 // Remember expected arguments in ecx. | 3047 // Remember expected arguments in ecx. |
| 2949 __ mov(ecx, ebx); | 3048 __ mov(ecx, ebx); |
| 2950 | 3049 |
| 2951 // Copy receiver and all actual arguments. | 3050 // Copy receiver and all actual arguments. |
| 2952 const int offset = StandardFrameConstants::kCallerSPOffset; | 3051 const int offset = StandardFrameConstants::kCallerSPOffset; |
| 2953 __ lea(edi, Operand(ebp, eax, times_4, offset)); | 3052 __ lea(edi, Operand(ebp, eax, times_4, offset)); |
| 2954 // ebx = expected - actual. | 3053 // ebx = expected - actual. |
| 2955 __ sub(ebx, eax); | 3054 __ sub(ebx, eax); |
| 2956 // eax = -actual - 1 | 3055 // eax = -actual - 1 |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3171 | 3270 |
| 3172 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { | 3271 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { |
| 3173 Generate_OnStackReplacementHelper(masm, true); | 3272 Generate_OnStackReplacementHelper(masm, true); |
| 3174 } | 3273 } |
| 3175 | 3274 |
| 3176 #undef __ | 3275 #undef __ |
| 3177 } // namespace internal | 3276 } // namespace internal |
| 3178 } // namespace v8 | 3277 } // namespace v8 |
| 3179 | 3278 |
| 3180 #endif // V8_TARGET_ARCH_IA32 | 3279 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |