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 |