| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #if defined(V8_TARGET_ARCH_X64) |
| 31 |
| 30 #include "codegen-inl.h" | 32 #include "codegen-inl.h" |
| 31 #include "ic-inl.h" | 33 #include "ic-inl.h" |
| 32 #include "runtime.h" | 34 #include "runtime.h" |
| 33 #include "stub-cache.h" | 35 #include "stub-cache.h" |
| 34 #include "utils.h" | 36 #include "utils.h" |
| 35 | 37 |
| 36 namespace v8 { | 38 namespace v8 { |
| 37 namespace internal { | 39 namespace internal { |
| 38 | 40 |
| 39 // ---------------------------------------------------------------------------- | 41 // ---------------------------------------------------------------------------- |
| (...skipping 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 771 IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1); | 773 IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1); |
| 772 | 774 |
| 773 __ bind(&slow); | 775 __ bind(&slow); |
| 774 GenerateMiss(masm); | 776 GenerateMiss(masm); |
| 775 } | 777 } |
| 776 | 778 |
| 777 | 779 |
| 778 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 780 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { |
| 779 // ----------- S t a t e ------------- | 781 // ----------- S t a t e ------------- |
| 780 // -- rax : value | 782 // -- rax : value |
| 783 // -- rcx : key |
| 784 // -- rdx : receiver |
| 781 // -- rsp[0] : return address | 785 // -- rsp[0] : return address |
| 782 // -- rsp[8] : key | |
| 783 // -- rsp[16] : receiver | |
| 784 // ----------------------------------- | 786 // ----------------------------------- |
| 785 | 787 |
| 786 __ pop(rcx); | 788 __ pop(rbx); |
| 787 __ push(Operand(rsp, 1 * kPointerSize)); // receiver | 789 __ push(rdx); // receiver |
| 788 __ push(Operand(rsp, 1 * kPointerSize)); // key | 790 __ push(rcx); // key |
| 789 __ push(rax); // value | 791 __ push(rax); // value |
| 790 __ push(rcx); // return address | 792 __ push(rbx); // return address |
| 791 | 793 |
| 792 // Do tail-call to runtime routine. | 794 // Do tail-call to runtime routine. |
| 793 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss)); | 795 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss)); |
| 794 __ TailCallExternalReference(ref, 3, 1); | 796 __ TailCallExternalReference(ref, 3, 1); |
| 795 } | 797 } |
| 796 | 798 |
| 797 | 799 |
| 798 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { | 800 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { |
| 799 // ----------- S t a t e ------------- | 801 // ----------- S t a t e ------------- |
| 800 // -- rax : value | 802 // -- rax : value |
| 803 // -- rcx : key |
| 804 // -- rdx : receiver |
| 801 // -- rsp[0] : return address | 805 // -- rsp[0] : return address |
| 802 // -- rsp[8] : key | |
| 803 // -- rsp[16] : receiver | |
| 804 // ----------------------------------- | 806 // ----------------------------------- |
| 805 | 807 |
| 806 __ pop(rcx); | 808 __ pop(rbx); |
| 807 __ push(Operand(rsp, 1 * kPointerSize)); // receiver | 809 __ push(rdx); // receiver |
| 808 __ push(Operand(rsp, 1 * kPointerSize)); // key | 810 __ push(rcx); // key |
| 809 __ push(rax); // value | 811 __ push(rax); // value |
| 810 __ push(rcx); // return address | 812 __ push(rbx); // return address |
| 811 | 813 |
| 812 // Do tail-call to runtime routine. | 814 // Do tail-call to runtime routine. |
| 813 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); | 815 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); |
| 814 } | 816 } |
| 815 | 817 |
| 816 | 818 |
| 817 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { | 819 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { |
| 818 // ----------- S t a t e ------------- | 820 // ----------- S t a t e ------------- |
| 819 // -- rax : value | 821 // -- rax : value |
| 820 // -- rsp[0] : return address | 822 // -- rcx : key |
| 821 // -- rsp[8] : key | 823 // -- rdx : receiver |
| 822 // -- rsp[16] : receiver | 824 // -- rsp[0] : return address |
| 823 // ----------------------------------- | 825 // ----------------------------------- |
| 824 Label slow, fast, array, extra, check_pixel_array; | 826 Label slow, fast, array, extra, check_pixel_array; |
| 825 | 827 |
| 826 // Get the receiver from the stack. | |
| 827 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // 2 ~ return address, key | |
| 828 // Check that the object isn't a smi. | 828 // Check that the object isn't a smi. |
| 829 __ JumpIfSmi(rdx, &slow); | 829 __ JumpIfSmi(rdx, &slow); |
| 830 // Get the map from the receiver. | 830 // Get the map from the receiver. |
| 831 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); | 831 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 832 // Check that the receiver does not require access checks. We need | 832 // Check that the receiver does not require access checks. We need |
| 833 // to do this because this generic stub does not perform map checks. | 833 // to do this because this generic stub does not perform map checks. |
| 834 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | 834 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 835 Immediate(1 << Map::kIsAccessCheckNeeded)); | 835 Immediate(1 << Map::kIsAccessCheckNeeded)); |
| 836 __ j(not_zero, &slow); | 836 __ j(not_zero, &slow); |
| 837 // Get the key from the stack. | |
| 838 __ movq(rbx, Operand(rsp, 1 * kPointerSize)); // 1 ~ return address | |
| 839 // Check that the key is a smi. | 837 // Check that the key is a smi. |
| 840 __ JumpIfNotSmi(rbx, &slow); | 838 __ JumpIfNotSmi(rcx, &slow); |
| 841 | 839 |
| 842 __ CmpInstanceType(rcx, JS_ARRAY_TYPE); | 840 __ CmpInstanceType(rbx, JS_ARRAY_TYPE); |
| 843 __ j(equal, &array); | 841 __ j(equal, &array); |
| 844 // Check that the object is some kind of JS object. | 842 // Check that the object is some kind of JS object. |
| 845 __ CmpInstanceType(rcx, FIRST_JS_OBJECT_TYPE); | 843 __ CmpInstanceType(rbx, FIRST_JS_OBJECT_TYPE); |
| 846 __ j(below, &slow); | 844 __ j(below, &slow); |
| 847 | 845 |
| 848 // Object case: Check key against length in the elements array. | 846 // Object case: Check key against length in the elements array. |
| 849 // rax: value | 847 // rax: value |
| 850 // rdx: JSObject | 848 // rdx: JSObject |
| 851 // rbx: index (as a smi) | 849 // rcx: index (as a smi) |
| 852 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); | 850 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 853 // Check that the object is in fast mode (not dictionary). | 851 // Check that the object is in fast mode (not dictionary). |
| 854 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | 852 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 855 Heap::kFixedArrayMapRootIndex); | 853 Heap::kFixedArrayMapRootIndex); |
| 856 __ j(not_equal, &check_pixel_array); | 854 __ j(not_equal, &check_pixel_array); |
| 857 // Untag the key (for checking against untagged length in the fixed array). | 855 // Untag the key (for checking against untagged length in the fixed array). |
| 858 __ SmiToInteger32(rdx, rbx); | 856 __ SmiToInteger32(rdi, rcx); |
| 859 __ cmpl(rdx, FieldOperand(rcx, Array::kLengthOffset)); | 857 __ cmpl(rdi, FieldOperand(rbx, Array::kLengthOffset)); |
| 860 // rax: value | 858 // rax: value |
| 861 // rcx: FixedArray | 859 // rbx: FixedArray |
| 862 // rbx: index (as a smi) | 860 // rcx: index (as a smi) |
| 863 __ j(below, &fast); | 861 __ j(below, &fast); |
| 864 | 862 |
| 865 // Slow case: call runtime. | 863 // Slow case: call runtime. |
| 866 __ bind(&slow); | 864 __ bind(&slow); |
| 867 GenerateRuntimeSetProperty(masm); | 865 GenerateRuntimeSetProperty(masm); |
| 868 | 866 |
| 869 // Check whether the elements is a pixel array. | 867 // Check whether the elements is a pixel array. |
| 870 // rax: value | 868 // rax: value |
| 871 // rcx: elements array | 869 // rdx: receiver |
| 872 // rbx: index (as a smi), zero-extended. | 870 // rbx: receiver's elements array |
| 871 // rcx: index (as a smi), zero-extended. |
| 873 __ bind(&check_pixel_array); | 872 __ bind(&check_pixel_array); |
| 874 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | 873 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 875 Heap::kPixelArrayMapRootIndex); | 874 Heap::kPixelArrayMapRootIndex); |
| 876 __ j(not_equal, &slow); | 875 __ j(not_equal, &slow); |
| 877 // Check that the value is a smi. If a conversion is needed call into the | 876 // Check that the value is a smi. If a conversion is needed call into the |
| 878 // runtime to convert and clamp. | 877 // runtime to convert and clamp. |
| 879 __ JumpIfNotSmi(rax, &slow); | 878 __ JumpIfNotSmi(rax, &slow); |
| 880 __ SmiToInteger32(rbx, rbx); | 879 __ SmiToInteger32(rdi, rcx); |
| 881 __ cmpl(rbx, FieldOperand(rcx, PixelArray::kLengthOffset)); | 880 __ cmpl(rdi, FieldOperand(rbx, PixelArray::kLengthOffset)); |
| 882 __ j(above_equal, &slow); | 881 __ j(above_equal, &slow); |
| 883 __ movq(rdx, rax); // Save the value. | 882 // No more bailouts to slow case on this path, so key not needed. |
| 884 __ SmiToInteger32(rax, rax); | 883 __ SmiToInteger32(rcx, rax); |
| 885 { // Clamp the value to [0..255]. | 884 { // Clamp the value to [0..255]. |
| 886 Label done; | 885 Label done; |
| 887 __ testl(rax, Immediate(0xFFFFFF00)); | 886 __ testl(rcx, Immediate(0xFFFFFF00)); |
| 888 __ j(zero, &done); | 887 __ j(zero, &done); |
| 889 __ setcc(negative, rax); // 1 if negative, 0 if positive. | 888 __ setcc(negative, rcx); // 1 if negative, 0 if positive. |
| 890 __ decb(rax); // 0 if negative, 255 if positive. | 889 __ decb(rcx); // 0 if negative, 255 if positive. |
| 891 __ bind(&done); | 890 __ bind(&done); |
| 892 } | 891 } |
| 893 __ movq(rcx, FieldOperand(rcx, PixelArray::kExternalPointerOffset)); | 892 __ movq(rbx, FieldOperand(rbx, PixelArray::kExternalPointerOffset)); |
| 894 __ movb(Operand(rcx, rbx, times_1, 0), rax); | 893 __ movb(Operand(rbx, rdi, times_1, 0), rcx); |
| 895 __ movq(rax, rdx); // Return the original value. | |
| 896 __ ret(0); | 894 __ ret(0); |
| 897 | 895 |
| 898 // Extra capacity case: Check if there is extra capacity to | 896 // Extra capacity case: Check if there is extra capacity to |
| 899 // perform the store and update the length. Used for adding one | 897 // perform the store and update the length. Used for adding one |
| 900 // element to the array by writing to array[array.length]. | 898 // element to the array by writing to array[array.length]. |
| 901 __ bind(&extra); | 899 __ bind(&extra); |
| 902 // rax: value | 900 // rax: value |
| 903 // rdx: JSArray | 901 // rdx: receiver (a JSArray) |
| 904 // rcx: FixedArray | 902 // rbx: receiver's elements array (a FixedArray) |
| 905 // rbx: index (as a smi) | 903 // rcx: index (as a smi) |
| 906 // flags: smicompare (rdx.length(), rbx) | 904 // flags: smicompare (rdx.length(), rbx) |
| 907 __ j(not_equal, &slow); // do not leave holes in the array | 905 __ j(not_equal, &slow); // do not leave holes in the array |
| 908 __ SmiToInteger64(rbx, rbx); | 906 __ SmiToInteger64(rdi, rcx); |
| 909 __ cmpl(rbx, FieldOperand(rcx, FixedArray::kLengthOffset)); | 907 __ cmpl(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); |
| 910 __ j(above_equal, &slow); | 908 __ j(above_equal, &slow); |
| 911 // Increment and restore smi-tag. | 909 // Increment and restore smi-tag. |
| 912 __ Integer64PlusConstantToSmi(rbx, rbx, 1); | 910 __ Integer64PlusConstantToSmi(rdi, rdi, 1); |
| 913 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rbx); | 911 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rdi); |
| 914 __ SmiSubConstant(rbx, rbx, Smi::FromInt(1)); | |
| 915 __ jmp(&fast); | 912 __ jmp(&fast); |
| 916 | 913 |
| 917 // Array case: Get the length and the elements array from the JS | 914 // Array case: Get the length and the elements array from the JS |
| 918 // array. Check that the array is in fast mode; if it is the | 915 // array. Check that the array is in fast mode; if it is the |
| 919 // length is always a smi. | 916 // length is always a smi. |
| 920 __ bind(&array); | 917 __ bind(&array); |
| 921 // rax: value | 918 // rax: value |
| 922 // rdx: JSArray | 919 // rdx: receiver (a JSArray) |
| 923 // rbx: index (as a smi) | 920 // rcx: index (as a smi) |
| 924 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); | 921 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 925 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | 922 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 926 Heap::kFixedArrayMapRootIndex); | 923 Heap::kFixedArrayMapRootIndex); |
| 927 __ j(not_equal, &slow); | 924 __ j(not_equal, &slow); |
| 928 | 925 |
| 929 // Check the key against the length in the array, compute the | 926 // Check the key against the length in the array, compute the |
| 930 // address to store into and fall through to fast case. | 927 // address to store into and fall through to fast case. |
| 931 __ SmiCompare(FieldOperand(rdx, JSArray::kLengthOffset), rbx); | 928 __ SmiCompare(FieldOperand(rdx, JSArray::kLengthOffset), rcx); |
| 932 __ j(below_equal, &extra); | 929 __ j(below_equal, &extra); |
| 933 | 930 |
| 934 // Fast case: Do the store. | 931 // Fast case: Do the store. |
| 935 __ bind(&fast); | 932 __ bind(&fast); |
| 936 // rax: value | 933 // rax: value |
| 937 // rcx: FixedArray | 934 // rbx: receiver's elements array (a FixedArray) |
| 938 // rbx: index (as a smi) | 935 // rcx: index (as a smi) |
| 939 Label non_smi_value; | 936 Label non_smi_value; |
| 940 __ JumpIfNotSmi(rax, &non_smi_value); | 937 __ JumpIfNotSmi(rax, &non_smi_value); |
| 941 SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2); | 938 SmiIndex index = masm->SmiToIndex(rcx, rcx, kPointerSizeLog2); |
| 942 __ movq(Operand(rcx, index.reg, index.scale, | 939 __ movq(Operand(rbx, index.reg, index.scale, |
| 943 FixedArray::kHeaderSize - kHeapObjectTag), | 940 FixedArray::kHeaderSize - kHeapObjectTag), |
| 944 rax); | 941 rax); |
| 945 __ ret(0); | 942 __ ret(0); |
| 946 __ bind(&non_smi_value); | 943 __ bind(&non_smi_value); |
| 947 // Slow case that needs to retain rbx for use by RecordWrite. | 944 // Slow case that needs to retain rcx for use by RecordWrite. |
| 948 // Update write barrier for the elements array address. | 945 // Update write barrier for the elements array address. |
| 949 SmiIndex index2 = masm->SmiToIndex(kScratchRegister, rbx, kPointerSizeLog2); | 946 SmiIndex index2 = masm->SmiToIndex(kScratchRegister, rcx, kPointerSizeLog2); |
| 950 __ movq(Operand(rcx, index2.reg, index2.scale, | 947 __ movq(Operand(rbx, index2.reg, index2.scale, |
| 951 FixedArray::kHeaderSize - kHeapObjectTag), | 948 FixedArray::kHeaderSize - kHeapObjectTag), |
| 952 rax); | 949 rax); |
| 953 __ movq(rdx, rax); | 950 __ movq(rdx, rax); |
| 954 __ RecordWriteNonSmi(rcx, 0, rdx, rbx); | 951 __ RecordWriteNonSmi(rbx, 0, rdx, rcx); |
| 955 __ ret(0); | 952 __ ret(0); |
| 956 } | 953 } |
| 957 | 954 |
| 958 | 955 |
| 959 void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, | 956 void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, |
| 960 ExternalArrayType array_type) { | 957 ExternalArrayType array_type) { |
| 961 // ----------- S t a t e ------------- | 958 // ----------- S t a t e ------------- |
| 962 // -- rax : value | 959 // -- rax : value |
| 963 // -- rsp[0] : return address | 960 // -- rcx : key |
| 964 // -- rsp[8] : key | 961 // -- rdx : receiver |
| 965 // -- rsp[16] : receiver | 962 // -- rsp[0] : return address |
| 966 // ----------------------------------- | 963 // ----------------------------------- |
| 967 Label slow, check_heap_number; | 964 Label slow, check_heap_number; |
| 968 | 965 |
| 969 // Get the receiver from the stack. | |
| 970 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); | |
| 971 // Check that the object isn't a smi. | 966 // Check that the object isn't a smi. |
| 972 __ JumpIfSmi(rdx, &slow); | 967 __ JumpIfSmi(rdx, &slow); |
| 973 // Get the map from the receiver. | 968 // Get the map from the receiver. |
| 974 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); | 969 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 975 // Check that the receiver does not require access checks. We need | 970 // Check that the receiver does not require access checks. We need |
| 976 // to do this because this generic stub does not perform map checks. | 971 // to do this because this generic stub does not perform map checks. |
| 977 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | 972 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 978 Immediate(1 << Map::kIsAccessCheckNeeded)); | 973 Immediate(1 << Map::kIsAccessCheckNeeded)); |
| 979 __ j(not_zero, &slow); | 974 __ j(not_zero, &slow); |
| 980 // Get the key from the stack. | |
| 981 __ movq(rbx, Operand(rsp, 1 * kPointerSize)); // 1 ~ return address | |
| 982 // Check that the key is a smi. | 975 // Check that the key is a smi. |
| 983 __ JumpIfNotSmi(rbx, &slow); | 976 __ JumpIfNotSmi(rcx, &slow); |
| 984 | 977 |
| 985 // Check that the object is a JS object. | 978 // Check that the object is a JS object. |
| 986 __ CmpInstanceType(rcx, JS_OBJECT_TYPE); | 979 __ CmpInstanceType(rbx, JS_OBJECT_TYPE); |
| 987 __ j(not_equal, &slow); | 980 __ j(not_equal, &slow); |
| 988 | 981 |
| 989 // Check that the elements array is the appropriate type of | 982 // Check that the elements array is the appropriate type of |
| 990 // ExternalArray. | 983 // ExternalArray. |
| 991 // rax: value | 984 // rax: value |
| 992 // rdx: JSObject | 985 // rcx: key (a smi) |
| 993 // rbx: index (as a smi) | 986 // rdx: receiver (a JSObject) |
| 994 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); | 987 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 995 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | 988 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 996 Heap::RootIndexForExternalArrayType(array_type)); | 989 Heap::RootIndexForExternalArrayType(array_type)); |
| 997 __ j(not_equal, &slow); | 990 __ j(not_equal, &slow); |
| 998 | 991 |
| 999 // Check that the index is in range. | 992 // Check that the index is in range. |
| 1000 __ SmiToInteger32(rbx, rbx); // Untag the index. | 993 __ SmiToInteger32(rdi, rcx); // Untag the index. |
| 1001 __ cmpl(rbx, FieldOperand(rcx, ExternalArray::kLengthOffset)); | 994 __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset)); |
| 1002 // Unsigned comparison catches both negative and too-large values. | 995 // Unsigned comparison catches both negative and too-large values. |
| 1003 __ j(above_equal, &slow); | 996 __ j(above_equal, &slow); |
| 1004 | 997 |
| 1005 // Handle both smis and HeapNumbers in the fast path. Go to the | 998 // Handle both smis and HeapNumbers in the fast path. Go to the |
| 1006 // runtime for all other kinds of values. | 999 // runtime for all other kinds of values. |
| 1007 // rax: value | 1000 // rax: value |
| 1008 // rcx: elements array | 1001 // rcx: key (a smi) |
| 1009 // rbx: untagged index | 1002 // rdx: receiver (a JSObject) |
| 1003 // rbx: elements array |
| 1004 // rdi: untagged key |
| 1010 __ JumpIfNotSmi(rax, &check_heap_number); | 1005 __ JumpIfNotSmi(rax, &check_heap_number); |
| 1011 __ movq(rdx, rax); // Save the value. | 1006 // No more branches to slow case on this path. Key and receiver not needed. |
| 1012 __ SmiToInteger32(rax, rax); | 1007 __ SmiToInteger32(rdx, rax); |
| 1013 __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset)); | 1008 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); |
| 1014 // rcx: base pointer of external storage | 1009 // rbx: base pointer of external storage |
| 1015 switch (array_type) { | 1010 switch (array_type) { |
| 1016 case kExternalByteArray: | 1011 case kExternalByteArray: |
| 1017 case kExternalUnsignedByteArray: | 1012 case kExternalUnsignedByteArray: |
| 1018 __ movb(Operand(rcx, rbx, times_1, 0), rax); | 1013 __ movb(Operand(rbx, rdi, times_1, 0), rdx); |
| 1019 break; | 1014 break; |
| 1020 case kExternalShortArray: | 1015 case kExternalShortArray: |
| 1021 case kExternalUnsignedShortArray: | 1016 case kExternalUnsignedShortArray: |
| 1022 __ movw(Operand(rcx, rbx, times_2, 0), rax); | 1017 __ movw(Operand(rbx, rdi, times_2, 0), rdx); |
| 1023 break; | 1018 break; |
| 1024 case kExternalIntArray: | 1019 case kExternalIntArray: |
| 1025 case kExternalUnsignedIntArray: | 1020 case kExternalUnsignedIntArray: |
| 1026 __ movl(Operand(rcx, rbx, times_4, 0), rax); | 1021 __ movl(Operand(rbx, rdi, times_4, 0), rdx); |
| 1027 break; | 1022 break; |
| 1028 case kExternalFloatArray: | 1023 case kExternalFloatArray: |
| 1029 // Need to perform int-to-float conversion. | 1024 // Need to perform int-to-float conversion. |
| 1030 __ push(rax); | 1025 __ push(rdx); |
| 1031 __ fild_s(Operand(rsp, 0)); | 1026 __ fild_s(Operand(rsp, 0)); |
| 1032 __ pop(rax); | 1027 __ pop(rdx); |
| 1033 __ fstp_s(Operand(rcx, rbx, times_4, 0)); | 1028 __ fstp_s(Operand(rbx, rdi, times_4, 0)); |
| 1034 break; | 1029 break; |
| 1035 default: | 1030 default: |
| 1036 UNREACHABLE(); | 1031 UNREACHABLE(); |
| 1037 break; | 1032 break; |
| 1038 } | 1033 } |
| 1039 __ movq(rax, rdx); // Return the original value. | |
| 1040 __ ret(0); | 1034 __ ret(0); |
| 1041 | 1035 |
| 1042 __ bind(&check_heap_number); | 1036 __ bind(&check_heap_number); |
| 1043 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rdx); | 1037 // rax: value |
| 1038 // rcx: key (a smi) |
| 1039 // rdx: receiver (a JSObject) |
| 1040 // rbx: elements array |
| 1041 // rdi: untagged key |
| 1042 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister); |
| 1044 __ j(not_equal, &slow); | 1043 __ j(not_equal, &slow); |
| 1044 // No more branches to slow case on this path. |
| 1045 | 1045 |
| 1046 // The WebGL specification leaves the behavior of storing NaN and | 1046 // The WebGL specification leaves the behavior of storing NaN and |
| 1047 // +/-Infinity into integer arrays basically undefined. For more | 1047 // +/-Infinity into integer arrays basically undefined. For more |
| 1048 // reproducible behavior, convert these to zero. | 1048 // reproducible behavior, convert these to zero. |
| 1049 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 1049 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
| 1050 __ movq(rdx, rax); // Save the value. | 1050 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); |
| 1051 __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset)); | 1051 // rdi: untagged index |
| 1052 // rbx: untagged index | 1052 // rbx: base pointer of external storage |
| 1053 // rcx: base pointer of external storage | |
| 1054 // top of FPU stack: value | 1053 // top of FPU stack: value |
| 1055 if (array_type == kExternalFloatArray) { | 1054 if (array_type == kExternalFloatArray) { |
| 1056 __ fstp_s(Operand(rcx, rbx, times_4, 0)); | 1055 __ fstp_s(Operand(rbx, rdi, times_4, 0)); |
| 1057 __ movq(rax, rdx); // Return the original value. | |
| 1058 __ ret(0); | 1056 __ ret(0); |
| 1059 } else { | 1057 } else { |
| 1060 // Need to perform float-to-int conversion. | 1058 // Need to perform float-to-int conversion. |
| 1061 // Test the top of the FP stack for NaN. | 1059 // Test the top of the FP stack for NaN. |
| 1062 Label is_nan; | 1060 Label is_nan; |
| 1063 __ fucomi(0); | 1061 __ fucomi(0); |
| 1064 __ j(parity_even, &is_nan); | 1062 __ j(parity_even, &is_nan); |
| 1065 | 1063 |
| 1066 __ push(rax); // Make room on stack | 1064 __ push(rdx); // Make room on the stack. Receiver is no longer needed. |
| 1067 __ fistp_d(Operand(rsp, 0)); | 1065 __ fistp_d(Operand(rsp, 0)); |
| 1068 __ pop(rax); | 1066 __ pop(rdx); |
| 1069 // rax: untagged integer value | 1067 // rdx: value (converted to an untagged integer) |
| 1068 // rdi: untagged index |
| 1069 // rbx: base pointer of external storage |
| 1070 switch (array_type) { | 1070 switch (array_type) { |
| 1071 case kExternalByteArray: | 1071 case kExternalByteArray: |
| 1072 case kExternalUnsignedByteArray: | 1072 case kExternalUnsignedByteArray: |
| 1073 __ movb(Operand(rcx, rbx, times_1, 0), rax); | 1073 __ movb(Operand(rbx, rdi, times_1, 0), rdx); |
| 1074 break; | 1074 break; |
| 1075 case kExternalShortArray: | 1075 case kExternalShortArray: |
| 1076 case kExternalUnsignedShortArray: | 1076 case kExternalUnsignedShortArray: |
| 1077 __ movw(Operand(rcx, rbx, times_2, 0), rax); | 1077 __ movw(Operand(rbx, rdi, times_2, 0), rdx); |
| 1078 break; | 1078 break; |
| 1079 case kExternalIntArray: | 1079 case kExternalIntArray: |
| 1080 case kExternalUnsignedIntArray: { | 1080 case kExternalUnsignedIntArray: { |
| 1081 // We also need to explicitly check for +/-Infinity. These are | 1081 // We also need to explicitly check for +/-Infinity. These are |
| 1082 // converted to MIN_INT, but we need to be careful not to | 1082 // converted to MIN_INT, but we need to be careful not to |
| 1083 // confuse with legal uses of MIN_INT. | 1083 // confuse with legal uses of MIN_INT. Since MIN_INT truncated |
| 1084 // to 8 or 16 bits is zero, we only perform this test when storing |
| 1085 // 32-bit ints. |
| 1084 Label not_infinity; | 1086 Label not_infinity; |
| 1085 // This test would apparently detect both NaN and Infinity, | 1087 // This test would apparently detect both NaN and Infinity, |
| 1086 // but we've already checked for NaN using the FPU hardware | 1088 // but we've already checked for NaN using the FPU hardware |
| 1087 // above. | 1089 // above. |
| 1088 __ movzxwq(rdi, FieldOperand(rdx, HeapNumber::kValueOffset + 6)); | 1090 __ movzxwq(rcx, FieldOperand(rax, HeapNumber::kValueOffset + 6)); |
| 1089 __ and_(rdi, Immediate(0x7FF0)); | 1091 __ and_(rcx, Immediate(0x7FF0)); |
| 1090 __ cmpw(rdi, Immediate(0x7FF0)); | 1092 __ cmpw(rcx, Immediate(0x7FF0)); |
| 1091 __ j(not_equal, ¬_infinity); | 1093 __ j(not_equal, ¬_infinity); |
| 1092 __ movq(rax, Immediate(0)); | 1094 __ movq(rdx, Immediate(0)); |
| 1093 __ bind(¬_infinity); | 1095 __ bind(¬_infinity); |
| 1094 __ movl(Operand(rcx, rbx, times_4, 0), rax); | 1096 __ movl(Operand(rbx, rdi, times_4, 0), rdx); |
| 1095 break; | 1097 break; |
| 1096 } | 1098 } |
| 1097 default: | 1099 default: |
| 1098 UNREACHABLE(); | 1100 UNREACHABLE(); |
| 1099 break; | 1101 break; |
| 1100 } | 1102 } |
| 1101 __ movq(rax, rdx); // Return the original value. | |
| 1102 __ ret(0); | 1103 __ ret(0); |
| 1103 | 1104 |
| 1104 __ bind(&is_nan); | 1105 __ bind(&is_nan); |
| 1106 // rdi: untagged index |
| 1107 // rbx: base pointer of external storage |
| 1105 __ ffree(); | 1108 __ ffree(); |
| 1106 __ fincstp(); | 1109 __ fincstp(); |
| 1107 __ movq(rax, Immediate(0)); | 1110 __ movq(rdx, Immediate(0)); |
| 1108 switch (array_type) { | 1111 switch (array_type) { |
| 1109 case kExternalByteArray: | 1112 case kExternalByteArray: |
| 1110 case kExternalUnsignedByteArray: | 1113 case kExternalUnsignedByteArray: |
| 1111 __ movb(Operand(rcx, rbx, times_1, 0), rax); | 1114 __ movb(Operand(rbx, rdi, times_1, 0), rdx); |
| 1112 break; | 1115 break; |
| 1113 case kExternalShortArray: | 1116 case kExternalShortArray: |
| 1114 case kExternalUnsignedShortArray: | 1117 case kExternalUnsignedShortArray: |
| 1115 __ movw(Operand(rcx, rbx, times_2, 0), rax); | 1118 __ movw(Operand(rbx, rdi, times_2, 0), rdx); |
| 1116 break; | 1119 break; |
| 1117 case kExternalIntArray: | 1120 case kExternalIntArray: |
| 1118 case kExternalUnsignedIntArray: | 1121 case kExternalUnsignedIntArray: |
| 1119 __ movl(Operand(rcx, rbx, times_4, 0), rax); | 1122 __ movl(Operand(rbx, rdi, times_4, 0), rdx); |
| 1120 break; | 1123 break; |
| 1121 default: | 1124 default: |
| 1122 UNREACHABLE(); | 1125 UNREACHABLE(); |
| 1123 break; | 1126 break; |
| 1124 } | 1127 } |
| 1125 __ movq(rax, rdx); // Return the original value. | |
| 1126 __ ret(0); | 1128 __ ret(0); |
| 1127 } | 1129 } |
| 1128 | 1130 |
| 1129 // Slow case: call runtime. | 1131 // Slow case: call runtime. |
| 1130 __ bind(&slow); | 1132 __ bind(&slow); |
| 1131 GenerateRuntimeSetProperty(masm); | 1133 GenerateRuntimeSetProperty(masm); |
| 1132 } | 1134 } |
| 1133 | 1135 |
| 1134 | 1136 |
| 1135 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 1137 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1612 __ bind(&miss); | 1614 __ bind(&miss); |
| 1613 | 1615 |
| 1614 GenerateMiss(masm); | 1616 GenerateMiss(masm); |
| 1615 } | 1617 } |
| 1616 | 1618 |
| 1617 | 1619 |
| 1618 #undef __ | 1620 #undef __ |
| 1619 | 1621 |
| 1620 | 1622 |
| 1621 } } // namespace v8::internal | 1623 } } // namespace v8::internal |
| 1624 |
| 1625 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |