Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: src/builtins/ia32/builtins-ia32.cc

Issue 2335513004: [Interpreter] Adds stackcheck in InterpreterPushArgsAndCall/Construct builtins. (Closed)
Patch Set: Reworked ia32 PushArgs builtin and addressed comments from Ross. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/arm64/builtins-arm64.cc ('k') | src/builtins/mips/builtins-mips.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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(&copy); 3030 __ bind(&copy);
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, &copy); 3035 __ j(less, &copy);
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
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
OLDNEW
« no previous file with comments | « src/builtins/arm64/builtins-arm64.cc ('k') | src/builtins/mips/builtins-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698