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

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

Issue 10991012: Fix 2346: Generic KeyedStoreIC doesn't change length and element_kind atomically (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | test/mjsunit/regress/regress-2346.js » ('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 // 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
(...skipping 729 matching lines...) Expand 10 before | Expand all | Expand 10 after
740 __ mov(unmapped_location, eax); 740 __ mov(unmapped_location, eax);
741 __ lea(edi, unmapped_location); 741 __ lea(edi, unmapped_location);
742 __ mov(edx, eax); 742 __ mov(edx, eax);
743 __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs); 743 __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
744 __ Ret(); 744 __ Ret();
745 __ bind(&slow); 745 __ bind(&slow);
746 GenerateMiss(masm, false); 746 GenerateMiss(masm, false);
747 } 747 }
748 748
749 749
750 static void KeyedStoreGeneratGenericHelper(MacroAssembler* masm,
Erik Corry 2012/09/25 09:26:26 Ken Thompson was once asked what he would do diffe
751 Label* fast_object,
752 Label* fast_double,
753 Label* slow,
754 bool check_map,
755 bool increment_length) {
756 Label transition_smi_elements;
757 Label finish_object_store, non_double_value, transition_double_elements;
758 Label fast_double_without_map_check;
759 // eax: value
760 // ecx: key (a smi)
761 // edx: receiver
762 // ebx: FixedArray receiver->elements
763 // edi: receiver map
764 // Fast case: Do the store, could either Object or double.
765 __ bind(fast_object);
766 if (check_map) {
767 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
768 __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
769 __ j(not_equal, fast_double);
770 }
771 // Smi stores don't require further checks.
772 Label non_smi_value;
773 __ JumpIfNotSmi(eax, &non_smi_value);
774 if (increment_length) {
775 // Add 1 to receiver->length, and go to common element store code for
776 // doubles.
777 __ add(FieldOperand(edx, JSArray::kLengthOffset),
778 Immediate(Smi::FromInt(1)));
779 }
780 // It's irrelevant whether array is smi-only or not when writing a smi.
781 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
782 __ ret(0);
783
784 __ bind(&non_smi_value);
785 // Escape to elements kind transition case.
786 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
787 __ CheckFastObjectElements(edi, &transition_smi_elements);
788
789 // Fast elements array, store the value to the elements backing store.
790 __ bind(&finish_object_store);
791 if (increment_length) {
792 // Add 1 to receiver->length, and go to common element store code for
793 // doubles.
794 __ add(FieldOperand(edx, JSArray::kLengthOffset),
795 Immediate(Smi::FromInt(1)));
796 }
797 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
798 // Update write barrier for the elements array address.
799 __ mov(edx, eax); // Preserve the value which is returned.
800 __ RecordWriteArray(
801 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
802 __ ret(0);
803
804 __ bind(fast_double);
805 if (check_map) {
806 // Check for fast double array case. If this fails, call through to the
807 // runtime.
808 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
809 __ j(not_equal, slow);
810 // If the value is a number, store it as a double in the FastDoubleElements
811 // array.
812 }
813 __ bind(&fast_double_without_map_check);
814 __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
815 &transition_double_elements, false);
816 if (increment_length) {
817 // Add 1 to receiver->length, and go to common element store code for
Erik Corry 2012/09/25 09:26:26 Comment out of date.
818 // doubles.
819 __ add(FieldOperand(edx, JSArray::kLengthOffset),
820 Immediate(Smi::FromInt(1)));
821 }
822 __ ret(0);
823
824 __ bind(&transition_smi_elements);
825 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
826
827 // Transition the array appropriately depending on the value type.
828 __ CheckMap(eax,
829 masm->isolate()->factory()->heap_number_map(),
830 &non_double_value,
831 DONT_DO_SMI_CHECK);
832
833 // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
834 // and complete the store.
835 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
836 FAST_DOUBLE_ELEMENTS,
837 ebx,
838 edi,
839 slow);
840 ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow);
841 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
842 __ jmp(&fast_double_without_map_check);
843
844 __ bind(&non_double_value);
845 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
846 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
847 FAST_ELEMENTS,
848 ebx,
849 edi,
850 slow);
851 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
852 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
853 __ jmp(&finish_object_store);
854
855 __ bind(&transition_double_elements);
856 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
857 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
858 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
859 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
860 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
861 FAST_ELEMENTS,
862 ebx,
863 edi,
864 slow);
865 ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow);
866 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
867 __ jmp(&finish_object_store);
868 }
869
Erik Corry 2012/09/25 09:26:26 Missing blank line.
750 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, 870 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
751 StrictModeFlag strict_mode) { 871 StrictModeFlag strict_mode) {
752 // ----------- S t a t e ------------- 872 // ----------- S t a t e -------------
753 // -- eax : value 873 // -- eax : value
754 // -- ecx : key 874 // -- ecx : key
755 // -- edx : receiver 875 // -- edx : receiver
756 // -- esp[0] : return address 876 // -- esp[0] : return address
757 // ----------------------------------- 877 // -----------------------------------
758 Label slow, fast_object_with_map_check, fast_object_without_map_check; 878 Label slow, fast_object, fast_object_grow;
759 Label fast_double_with_map_check, fast_double_without_map_check; 879 Label fast_double, fast_double_grow;
760 Label check_if_double_array, array, extra, transition_smi_elements; 880 Label array, extra, check_if_double_array;
761 Label finish_object_store, non_double_value, transition_double_elements;
762 881
763 // Check that the object isn't a smi. 882 // Check that the object isn't a smi.
764 __ JumpIfSmi(edx, &slow); 883 __ JumpIfSmi(edx, &slow);
765 // Get the map from the receiver. 884 // Get the map from the receiver.
766 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 885 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
767 // Check that the receiver does not require access checks. We need 886 // Check that the receiver does not require access checks. We need
768 // to do this because this generic stub does not perform map checks. 887 // to do this because this generic stub does not perform map checks.
769 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), 888 __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
770 1 << Map::kIsAccessCheckNeeded); 889 1 << Map::kIsAccessCheckNeeded);
771 __ j(not_zero, &slow); 890 __ j(not_zero, &slow);
772 // Check that the key is a smi. 891 // Check that the key is a smi.
773 __ JumpIfNotSmi(ecx, &slow); 892 __ JumpIfNotSmi(ecx, &slow);
774 __ CmpInstanceType(edi, JS_ARRAY_TYPE); 893 __ CmpInstanceType(edi, JS_ARRAY_TYPE);
775 __ j(equal, &array); 894 __ j(equal, &array);
776 // Check that the object is some kind of JSObject. 895 // Check that the object is some kind of JSObject.
777 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); 896 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
778 __ j(below, &slow); 897 __ j(below, &slow);
779 898
780 // Object case: Check key against length in the elements array. 899 // Object case: Check key against length in the elements array.
781 // eax: value 900 // eax: value
782 // edx: JSObject 901 // edx: JSObject
783 // ecx: key (a smi) 902 // ecx: key (a smi)
784 // edi: receiver map 903 // edi: receiver map
785 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 904 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
786 // Check array bounds. Both the key and the length of FixedArray are smis. 905 // Check array bounds. Both the key and the length of FixedArray are smis.
787 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); 906 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
788 __ j(below, &fast_object_with_map_check); 907 __ j(below, &fast_object);
789 908
790 // Slow case: call runtime. 909 // Slow case: call runtime.
791 __ bind(&slow); 910 __ bind(&slow);
792 GenerateRuntimeSetProperty(masm, strict_mode); 911 GenerateRuntimeSetProperty(masm, strict_mode);
793 912
794 // Extra capacity case: Check if there is extra capacity to 913 // Extra capacity case: Check if there is extra capacity to
795 // perform the store and update the length. Used for adding one 914 // perform the store and update the length. Used for adding one
796 // element to the array by writing to array[array.length]. 915 // element to the array by writing to array[array.length].
797 __ bind(&extra); 916 __ bind(&extra);
798 // eax: value 917 // eax: value
799 // edx: receiver, a JSArray 918 // edx: receiver, a JSArray
800 // ecx: key, a smi. 919 // ecx: key, a smi.
801 // ebx: receiver->elements, a FixedArray 920 // ebx: receiver->elements, a FixedArray
802 // edi: receiver map 921 // edi: receiver map
803 // flags: compare (ecx, edx.length()) 922 // flags: compare (ecx, edx.length())
804 // do not leave holes in the array: 923 // do not leave holes in the array:
805 __ j(not_equal, &slow); 924 __ j(not_equal, &slow);
806 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); 925 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
807 __ j(above_equal, &slow); 926 __ j(above_equal, &slow);
808 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset)); 927 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
809 __ cmp(edi, masm->isolate()->factory()->fixed_array_map()); 928 __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
810 __ j(not_equal, &check_if_double_array); 929 __ j(not_equal, &check_if_double_array);
811 // Add 1 to receiver->length, and go to common element store code for Objects. 930 __ jmp(&fast_object_grow);
812 __ add(FieldOperand(edx, JSArray::kLengthOffset),
813 Immediate(Smi::FromInt(1)));
814 __ jmp(&fast_object_without_map_check);
815 931
816 __ bind(&check_if_double_array); 932 __ bind(&check_if_double_array);
817 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map()); 933 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
818 __ j(not_equal, &slow); 934 __ j(not_equal, &slow);
819 // Add 1 to receiver->length, and go to common element store code for doubles. 935 __ jmp(&fast_double_grow);
820 __ add(FieldOperand(edx, JSArray::kLengthOffset),
821 Immediate(Smi::FromInt(1)));
822 __ jmp(&fast_double_without_map_check);
823 936
824 // Array case: Get the length and the elements array from the JS 937 // Array case: Get the length and the elements array from the JS
825 // array. Check that the array is in fast mode (and writable); if it 938 // array. Check that the array is in fast mode (and writable); if it
826 // is the length is always a smi. 939 // is the length is always a smi.
827 __ bind(&array); 940 __ bind(&array);
828 // eax: value 941 // eax: value
829 // edx: receiver, a JSArray 942 // edx: receiver, a JSArray
830 // ecx: key, a smi. 943 // ecx: key, a smi.
831 // edi: receiver map 944 // edi: receiver map
832 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 945 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
833 946
834 // Check the key against the length in the array and fall through to the 947 // Check the key against the length in the array and fall through to the
835 // common store code. 948 // common store code.
836 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. 949 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
837 __ j(above_equal, &extra); 950 __ j(above_equal, &extra);
838 951
839 // Fast case: Do the store, could either Object or double. 952 KeyedStoreGeneratGenericHelper(masm, &fast_object, &fast_double, &slow,
840 __ bind(&fast_object_with_map_check); 953 true, false);
841 // eax: value 954 KeyedStoreGeneratGenericHelper(masm, &fast_object_grow, &fast_double_grow,
842 // ecx: key (a smi) 955 &slow, false, true);
843 // edx: receiver
844 // ebx: FixedArray receiver->elements
845 // edi: receiver map
846 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
847 __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
848 __ j(not_equal, &fast_double_with_map_check);
849 __ bind(&fast_object_without_map_check);
850 // Smi stores don't require further checks.
851 Label non_smi_value;
852 __ JumpIfNotSmi(eax, &non_smi_value);
853 // It's irrelevant whether array is smi-only or not when writing a smi.
854 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
855 __ ret(0);
856
857 __ bind(&non_smi_value);
858 // Escape to elements kind transition case.
859 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
860 __ CheckFastObjectElements(edi, &transition_smi_elements);
861
862 // Fast elements array, store the value to the elements backing store.
863 __ bind(&finish_object_store);
864 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
865 // Update write barrier for the elements array address.
866 __ mov(edx, eax); // Preserve the value which is returned.
867 __ RecordWriteArray(
868 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
869 __ ret(0);
870
871 __ bind(&fast_double_with_map_check);
872 // Check for fast double array case. If this fails, call through to the
873 // runtime.
874 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
875 __ j(not_equal, &slow);
876 __ bind(&fast_double_without_map_check);
877 // If the value is a number, store it as a double in the FastDoubleElements
878 // array.
879 __ StoreNumberToDoubleElements(eax, ebx, ecx, edx, xmm0,
880 &transition_double_elements, false);
881 __ ret(0);
882
883 __ bind(&transition_smi_elements);
884 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
885
886 // Transition the array appropriately depending on the value type.
887 __ CheckMap(eax,
888 masm->isolate()->factory()->heap_number_map(),
889 &non_double_value,
890 DONT_DO_SMI_CHECK);
891
892 // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
893 // and complete the store.
894 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
895 FAST_DOUBLE_ELEMENTS,
896 ebx,
897 edi,
898 &slow);
899 ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow);
900 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
901 __ jmp(&fast_double_without_map_check);
902
903 __ bind(&non_double_value);
904 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
905 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
906 FAST_ELEMENTS,
907 ebx,
908 edi,
909 &slow);
910 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
911 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
912 __ jmp(&finish_object_store);
913
914 __ bind(&transition_double_elements);
915 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
916 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
917 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
918 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
919 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
920 FAST_ELEMENTS,
921 ebx,
922 edi,
923 &slow);
924 ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
925 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
926 __ jmp(&finish_object_store);
927 } 956 }
928 957
929 958
930 // The generated code does not accept smi keys. 959 // The generated code does not accept smi keys.
931 // The generated code falls through if both probes miss. 960 // The generated code falls through if both probes miss.
932 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, 961 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
933 int argc, 962 int argc,
934 Code::Kind kind, 963 Code::Kind kind,
935 Code::ExtraICState extra_state) { 964 Code::ExtraICState extra_state) {
936 // ----------- S t a t e ------------- 965 // ----------- S t a t e -------------
(...skipping 828 matching lines...) Expand 10 before | Expand all | Expand 10 after
1765 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) 1794 Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
1766 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) 1795 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
1767 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); 1796 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
1768 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); 1797 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
1769 } 1798 }
1770 1799
1771 1800
1772 } } // namespace v8::internal 1801 } } // namespace v8::internal
1773 1802
1774 #endif // V8_TARGET_ARCH_IA32 1803 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/regress/regress-2346.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698