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 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 __ push(edi); | 698 __ push(edi); |
699 __ CallRuntime(Runtime::kCompileBaseline); | 699 __ CallRuntime(Runtime::kCompileBaseline); |
700 | 700 |
701 // Restore return value. | 701 // Restore return value. |
702 __ pop(eax); | 702 __ pop(eax); |
703 } | 703 } |
704 __ ret(0); | 704 __ ret(0); |
705 } | 705 } |
706 | 706 |
707 static void Generate_InterpreterPushArgs(MacroAssembler* masm, | 707 static void Generate_InterpreterPushArgs(MacroAssembler* masm, |
708 Register array_limit) { | 708 Register array_limit, |
| 709 Register start_address) { |
709 // ----------- S t a t e ------------- | 710 // ----------- S t a t e ------------- |
710 // -- ebx : Pointer to the last argument in the args array. | 711 // -- start_address : Pointer to the last argument in the args array. |
711 // -- array_limit : Pointer to one before the first argument in the | 712 // -- array_limit : Pointer to one before the first argument in the |
712 // args array. | 713 // args array. |
713 // ----------------------------------- | 714 // ----------------------------------- |
714 Label loop_header, loop_check; | 715 Label loop_header, loop_check; |
715 __ jmp(&loop_check); | 716 __ jmp(&loop_check); |
716 __ bind(&loop_header); | 717 __ bind(&loop_header); |
717 __ Push(Operand(ebx, 0)); | 718 __ Push(Operand(start_address, 0)); |
718 __ sub(ebx, Immediate(kPointerSize)); | 719 __ sub(start_address, Immediate(kPointerSize)); |
719 __ bind(&loop_check); | 720 __ bind(&loop_check); |
720 __ cmp(ebx, array_limit); | 721 __ cmp(start_address, array_limit); |
721 __ j(greater, &loop_header, Label::kNear); | 722 __ j(greater, &loop_header, Label::kNear); |
722 } | 723 } |
723 | 724 |
724 // static | 725 // static |
725 void Builtins::Generate_InterpreterPushArgsAndCallImpl( | 726 void Builtins::Generate_InterpreterPushArgsAndCallImpl( |
726 MacroAssembler* masm, TailCallMode tail_call_mode, | 727 MacroAssembler* masm, TailCallMode tail_call_mode, |
727 CallableType function_type) { | 728 CallableType function_type) { |
728 // ----------- S t a t e ------------- | 729 // ----------- S t a t e ------------- |
729 // -- eax : the number of arguments (not including the receiver) | 730 // -- eax : the number of arguments (not including the receiver) |
730 // -- ebx : the address of the first argument to be pushed. Subsequent | 731 // -- ebx : the address of the first argument to be pushed. Subsequent |
731 // arguments should be consecutive above this, in the same order as | 732 // arguments should be consecutive above this, in the same order as |
732 // they are to be pushed onto the stack. | 733 // they are to be pushed onto the stack. |
733 // -- edi : the target to call (can be any Object). | 734 // -- edi : the target to call (can be any Object). |
734 // ----------------------------------- | 735 // ----------------------------------- |
735 | 736 |
736 // Pop return address to allow tail-call after pushing arguments. | 737 // Pop return address to allow tail-call after pushing arguments. |
737 __ Pop(edx); | 738 __ Pop(edx); |
738 | 739 |
739 // Find the address of the last argument. | 740 // Find the address of the last argument. |
740 __ mov(ecx, eax); | 741 __ mov(ecx, eax); |
741 __ add(ecx, Immediate(1)); // Add one for receiver. | 742 __ add(ecx, Immediate(1)); // Add one for receiver. |
742 __ shl(ecx, kPointerSizeLog2); | 743 __ shl(ecx, kPointerSizeLog2); |
743 __ neg(ecx); | 744 __ neg(ecx); |
744 __ add(ecx, ebx); | 745 __ add(ecx, ebx); |
745 | 746 |
746 Generate_InterpreterPushArgs(masm, ecx); | 747 // TODO(mythria): Add a stack check before pushing the arguments. |
| 748 Generate_InterpreterPushArgs(masm, ecx, ebx); |
747 | 749 |
748 // Call the target. | 750 // Call the target. |
749 __ Push(edx); // Re-push return address. | 751 __ Push(edx); // Re-push return address. |
750 | 752 |
751 if (function_type == CallableType::kJSFunction) { | 753 if (function_type == CallableType::kJSFunction) { |
752 __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, | 754 __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, |
753 tail_call_mode), | 755 tail_call_mode), |
754 RelocInfo::CODE_TARGET); | 756 RelocInfo::CODE_TARGET); |
755 } else { | 757 } else { |
756 DCHECK_EQ(function_type, CallableType::kAny); | 758 DCHECK_EQ(function_type, CallableType::kAny); |
757 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, | 759 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, |
758 tail_call_mode), | 760 tail_call_mode), |
759 RelocInfo::CODE_TARGET); | 761 RelocInfo::CODE_TARGET); |
760 } | 762 } |
761 } | 763 } |
762 | 764 |
763 // static | 765 // static |
764 void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { | 766 void Builtins::Generate_InterpreterPushArgsAndConstructImpl( |
| 767 MacroAssembler* masm, CallableType construct_type) { |
765 // ----------- S t a t e ------------- | 768 // ----------- S t a t e ------------- |
766 // -- eax : the number of arguments (not including the receiver) | 769 // -- eax : the number of arguments (not including the receiver) |
767 // -- edx : the new target | 770 // -- edx : the new target |
768 // -- edi : the constructor | 771 // -- edi : the constructor |
769 // -- ebx : the address of the first argument to be pushed. Subsequent | 772 // -- ebx : allocation site feedback (if available or undefined) |
| 773 // -- ecx : the address of the first argument to be pushed. Subsequent |
770 // arguments should be consecutive above this, in the same order as | 774 // arguments should be consecutive above this, in the same order as |
771 // they are to be pushed onto the stack. | 775 // they are to be pushed onto the stack. |
772 // ----------------------------------- | 776 // ----------------------------------- |
773 | 777 |
774 // Pop return address to allow tail-call after pushing arguments. | 778 // Store edi, edx onto the stack. We need two extra registers |
775 __ Pop(ecx); | 779 // so store edi, edx temporarily on stack. |
| 780 __ Push(edi); |
| 781 __ Push(edx); |
776 | 782 |
777 // Push edi in the slot meant for receiver. We need an extra register | 783 // We have to pop return address and the two temporary registers before we |
778 // so store edi temporarily on stack. | 784 // can push arguments onto the stack. we do not have any free registers so |
779 __ Push(edi); | 785 // update the stack and copy them into the correct places on the stack. |
| 786 // current stack =====> required stack layout |
| 787 // | | | edx | (2) <-- esp(1) |
| 788 // | | | edi | (3) |
| 789 // | | | return addr | (4) |
| 790 // | | | arg N | (5) |
| 791 // | edx | <-- esp | .... | |
| 792 // | edi | | arg 0 | |
| 793 // | return addr | | receiver slot | |
780 | 794 |
781 // Find the address of the last argument. | 795 // First increment the stack pointer to the correct location. |
782 __ mov(edi, eax); | 796 // we need additional slots for arguments and the receiver. |
783 __ neg(edi); | 797 // Step 1 - compute the required increment to the stack. |
784 __ shl(edi, kPointerSizeLog2); | 798 __ mov(edx, eax); |
785 __ add(edi, ebx); | 799 __ shl(edx, kPointerSizeLog2); |
| 800 __ add(edx, Immediate(kPointerSize)); |
786 | 801 |
787 Generate_InterpreterPushArgs(masm, edi); | 802 #ifdef _MSC_VER |
| 803 // TODO(mythria): Move it to macro assembler. |
| 804 // In windows, we cannot increment the stack size by more than one page |
| 805 // (mimimum page size is 4KB) without accessing at least one byte on the |
| 806 // page. Check this: |
| 807 // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. |
| 808 const int page_size = 4 * 1024; |
| 809 Label check_offset, update_stack_pointer; |
| 810 __ bind(&check_offset); |
| 811 __ cmp(edx, page_size); |
| 812 __ j(less, &update_stack_pointer); |
| 813 __ sub(esp, Immediate(page_size)); |
| 814 // Just to touch the page, before we increment further. |
| 815 __ mov(Operand(esp, 0), Immediate(0)); |
| 816 __ sub(edx, Immediate(page_size)); |
| 817 __ jmp(&check_offset); |
| 818 __ bind(&update_stack_pointer); |
| 819 #endif |
788 | 820 |
789 // Restore the constructor from slot on stack. It was pushed at the slot | 821 // TODO(mythria): Add a stack check before updating the stack pointer. |
790 // meant for receiver. | |
791 __ mov(edi, Operand(esp, eax, times_pointer_size, 0)); | |
792 | 822 |
793 // Re-push return address. | 823 // Step 1 - Update the stack pointer. |
794 __ Push(ecx); | 824 __ sub(esp, edx); |
795 | 825 |
796 // Call the constructor with unmodified eax, edi, ebi values. | 826 // Step 2 move edx to the correct location. Move edx first otherwise |
797 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 827 // we may overwrite when eax = 0 or 1, basically when the source and |
| 828 // destination overlap. We at least need one extra slot for receiver, |
| 829 // so no extra checks are required to avoid copy. |
| 830 __ mov(edi, Operand(esp, eax, times_pointer_size, 1 * kPointerSize)); |
| 831 __ mov(Operand(esp, 0), edi); |
| 832 |
| 833 // Step 3 move edi to the correct location |
| 834 __ mov(edi, Operand(esp, eax, times_pointer_size, 2 * kPointerSize)); |
| 835 __ mov(Operand(esp, 1 * kPointerSize), edi); |
| 836 |
| 837 // Step 4 move return address to the correct location |
| 838 __ mov(edi, Operand(esp, eax, times_pointer_size, 3 * kPointerSize)); |
| 839 __ mov(Operand(esp, 2 * kPointerSize), edi); |
| 840 |
| 841 // Slot meant for receiver contains return address. Reset it so that |
| 842 // we will not incorrectly interpret return address as an object. |
| 843 __ mov(Operand(esp, eax, times_pointer_size, 3 * kPointerSize), Immediate(0)); |
| 844 |
| 845 // Step 5 copy arguments to correct locations. |
| 846 __ mov(edx, eax); |
| 847 |
| 848 Label loop_header, loop_check; |
| 849 __ jmp(&loop_check); |
| 850 __ bind(&loop_header); |
| 851 __ mov(edi, Operand(ecx, 0)); |
| 852 __ mov(Operand(esp, edx, times_pointer_size, 2 * kPointerSize), edi); |
| 853 __ sub(ecx, Immediate(kPointerSize)); |
| 854 __ sub(edx, Immediate(1)); |
| 855 __ bind(&loop_check); |
| 856 __ cmp(edx, Immediate(0)); |
| 857 __ j(greater, &loop_header, Label::kNear); |
| 858 |
| 859 // Restore edi and edx. |
| 860 __ Pop(edx); |
| 861 __ Pop(edi); |
| 862 |
| 863 __ AssertUndefinedOrAllocationSite(ebx); |
| 864 if (construct_type == CallableType::kJSFunction) { |
| 865 // Tail call to the function-specific construct stub (still in the caller |
| 866 // context at this point). |
| 867 __ AssertFunction(edi); |
| 868 |
| 869 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 870 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); |
| 871 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); |
| 872 __ jmp(ecx); |
| 873 } else { |
| 874 DCHECK_EQ(construct_type, CallableType::kAny); |
| 875 |
| 876 // Call the constructor with unmodified eax, edi, edx values. |
| 877 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
| 878 } |
798 } | 879 } |
799 | 880 |
800 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { | 881 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { |
801 // Set the return address to the correct point in the interpreter entry | 882 // Set the return address to the correct point in the interpreter entry |
802 // trampoline. | 883 // trampoline. |
803 Smi* interpreter_entry_return_pc_offset( | 884 Smi* interpreter_entry_return_pc_offset( |
804 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); | 885 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); |
805 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); | 886 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0)); |
806 __ LoadHeapObject(ebx, | 887 __ LoadHeapObject(ebx, |
807 masm->isolate()->builtins()->InterpreterEntryTrampoline()); | 888 masm->isolate()->builtins()->InterpreterEntryTrampoline()); |
(...skipping 2257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3065 | 3146 |
3066 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { | 3147 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { |
3067 Generate_OnStackReplacementHelper(masm, true); | 3148 Generate_OnStackReplacementHelper(masm, true); |
3068 } | 3149 } |
3069 | 3150 |
3070 #undef __ | 3151 #undef __ |
3071 } // namespace internal | 3152 } // namespace internal |
3072 } // namespace v8 | 3153 } // namespace v8 |
3073 | 3154 |
3074 #endif // V8_TARGET_ARCH_X87 | 3155 #endif // V8_TARGET_ARCH_X87 |
OLD | NEW |