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