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

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

Issue 661245: Faster filling newly allocated arrays with the holes from the Array construction stub. (Closed)
Patch Set: scons -> stos as spotted by Soren Created 10 years, 9 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
« no previous file with comments | « src/ia32/assembler-ia32.cc ('k') | src/ia32/disasm-ia32.cc » ('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 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 779 matching lines...) Expand 10 before | Expand all | Expand 10 after
790 // register array_function holds the built-in Array function and the register 790 // register array_function holds the built-in Array function and the register
791 // array_size holds the size of the array as a smi. The allocated array is put 791 // array_size holds the size of the array as a smi. The allocated array is put
792 // into the result register and beginning and end of the FixedArray elements 792 // into the result register and beginning and end of the FixedArray elements
793 // storage is put into registers elements_array and elements_array_end (see 793 // storage is put into registers elements_array and elements_array_end (see
794 // below for when that is not the case). If the parameter fill_with_holes is 794 // below for when that is not the case). If the parameter fill_with_holes is
795 // true the allocated elements backing store is filled with the hole values 795 // true the allocated elements backing store is filled with the hole values
796 // otherwise it is left uninitialized. When the backing store is filled the 796 // otherwise it is left uninitialized. When the backing store is filled the
797 // register elements_array is scratched. 797 // register elements_array is scratched.
798 static void AllocateJSArray(MacroAssembler* masm, 798 static void AllocateJSArray(MacroAssembler* masm,
799 Register array_function, // Array function. 799 Register array_function, // Array function.
800 Register array_size, // As a smi. 800 Register array_size, // As a smi, cannot be 0.
801 Register result, 801 Register result,
802 Register elements_array, 802 Register elements_array,
803 Register elements_array_end, 803 Register elements_array_end,
804 Register scratch, 804 Register scratch,
805 bool fill_with_hole, 805 bool fill_with_hole,
806 Label* gc_required) { 806 Label* gc_required) {
807 Label not_empty, allocated; 807 ASSERT(scratch.is(edi)); // rep stos destination
808 ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
808 809
809 // Load the initial map from the array function. 810 // Load the initial map from the array function.
810 __ mov(elements_array, 811 __ mov(elements_array,
811 FieldOperand(array_function, 812 FieldOperand(array_function,
812 JSFunction::kPrototypeOrInitialMapOffset)); 813 JSFunction::kPrototypeOrInitialMapOffset));
813 814
814 // Check whether an empty sized array is requested.
815 __ test(array_size, Operand(array_size));
816 __ j(not_zero, &not_empty);
817
818 // If an empty array is requested allocate a small elements array anyway. This
819 // keeps the code below free of special casing for the empty array.
820 int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
821 __ AllocateInNewSpace(size,
822 result,
823 elements_array_end,
824 scratch,
825 gc_required,
826 TAG_OBJECT);
827 __ jmp(&allocated);
828
829 // Allocate the JSArray object together with space for a FixedArray with the 815 // Allocate the JSArray object together with space for a FixedArray with the
830 // requested elements. 816 // requested elements.
831 __ bind(&not_empty);
832 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 817 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
833 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, 818 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
834 times_half_pointer_size, // array_size is a smi. 819 times_half_pointer_size, // array_size is a smi.
835 array_size, 820 array_size,
836 result, 821 result,
837 elements_array_end, 822 elements_array_end,
838 scratch, 823 scratch,
839 gc_required, 824 gc_required,
840 TAG_OBJECT); 825 TAG_OBJECT);
841 826
842 // Allocated the JSArray. Now initialize the fields except for the elements 827 // Allocated the JSArray. Now initialize the fields except for the elements
843 // array. 828 // array.
844 // result: JSObject 829 // result: JSObject
845 // elements_array: initial map 830 // elements_array: initial map
846 // elements_array_end: start of next object 831 // elements_array_end: start of next object
847 // array_size: size of array (smi) 832 // array_size: size of array (smi)
848 __ bind(&allocated);
849 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array); 833 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
850 __ mov(elements_array, Factory::empty_fixed_array()); 834 __ mov(elements_array, Factory::empty_fixed_array());
851 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array); 835 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
852 // Field JSArray::kElementsOffset is initialized later. 836 // Field JSArray::kElementsOffset is initialized later.
853 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size); 837 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
854 838
855 // Calculate the location of the elements array and set elements array member 839 // Calculate the location of the elements array and set elements array member
856 // of the JSArray. 840 // of the JSArray.
857 // result: JSObject 841 // result: JSObject
858 // elements_array_end: start of next object 842 // elements_array_end: start of next object
859 // array_size: size of array (smi) 843 // array_size: size of array (smi)
860 __ lea(elements_array, Operand(result, JSArray::kSize)); 844 __ lea(elements_array, Operand(result, JSArray::kSize));
861 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array); 845 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
862 846
863 // Initialize the fixed array. FixedArray length is not stored as a smi. 847 // Initialize the fixed array. FixedArray length is not stored as a smi.
864 // result: JSObject 848 // result: JSObject
865 // elements_array: elements array 849 // elements_array: elements array
866 // elements_array_end: start of next object 850 // elements_array_end: start of next object
867 // array_size: size of array (smi) 851 // array_size: size of array (smi)
868 ASSERT(kSmiTag == 0); 852 ASSERT(kSmiTag == 0);
869 __ SmiUntag(array_size); // Convert from smi to value. 853 __ SmiUntag(array_size); // Convert from smi to value.
870 __ mov(FieldOperand(elements_array, JSObject::kMapOffset), 854 __ mov(FieldOperand(elements_array, JSObject::kMapOffset),
871 Factory::fixed_array_map()); 855 Factory::fixed_array_map());
872 Label not_empty_2, fill_array;
873 __ test(array_size, Operand(array_size));
874 __ j(not_zero, &not_empty_2);
875 // Length of the FixedArray is the number of pre-allocated elements even
876 // though the actual JSArray has length 0.
877 __ mov(FieldOperand(elements_array, Array::kLengthOffset),
878 Immediate(kPreallocatedArrayElements));
879 __ jmp(&fill_array);
880 __ bind(&not_empty_2);
881 // For non-empty JSArrays the length of the FixedArray and the JSArray is the 856 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
882 // same. 857 // same.
883 __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size); 858 __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size);
884 859
885 // Fill the allocated FixedArray with the hole value if requested. 860 // Fill the allocated FixedArray with the hole value if requested.
886 // result: JSObject 861 // result: JSObject
887 // elements_array: elements array 862 // elements_array: elements array
888 // elements_array_end: start of next object
889 __ bind(&fill_array);
890 if (fill_with_hole) { 863 if (fill_with_hole) {
891 Label loop, entry; 864 __ lea(edi, Operand(elements_array,
892 __ mov(scratch, Factory::the_hole_value()); 865 FixedArray::kHeaderSize - kHeapObjectTag));
893 __ lea(elements_array, Operand(elements_array, 866
894 FixedArray::kHeaderSize - kHeapObjectTag)); 867 __ push(eax);
895 __ jmp(&entry); 868 __ mov(eax, Factory::the_hole_value());
896 __ bind(&loop); 869
897 __ mov(Operand(elements_array, 0), scratch); 870 __ cld();
898 __ add(Operand(elements_array), Immediate(kPointerSize)); 871 __ rep_stos();
899 __ bind(&entry); 872
900 __ cmp(elements_array, Operand(elements_array_end)); 873 // Restore saved registers.
901 __ j(below, &loop); 874 __ pop(eax);
902 } 875 }
903 } 876 }
904 877
905 878
906 // Create a new array for the built-in Array function. This function allocates 879 // Create a new array for the built-in Array function. This function allocates
907 // the JSArray object and the FixedArray elements array and initializes these. 880 // the JSArray object and the FixedArray elements array and initializes these.
908 // If the Array cannot be constructed in native code the runtime is called. This 881 // If the Array cannot be constructed in native code the runtime is called. This
909 // function assumes the following state: 882 // function assumes the following state:
910 // edi: constructor (built-in Array function) 883 // edi: constructor (built-in Array function)
911 // eax: argc 884 // eax: argc
912 // esp[0]: return address 885 // esp[0]: return address
913 // esp[4]: last argument 886 // esp[4]: last argument
914 // This function is used for both construct and normal calls of Array. Whether 887 // This function is used for both construct and normal calls of Array. Whether
915 // it is a construct call or not is indicated by the construct_call parameter. 888 // it is a construct call or not is indicated by the construct_call parameter.
916 // The only difference between handling a construct call and a normal call is 889 // The only difference between handling a construct call and a normal call is
917 // that for a construct call the constructor function in edi needs to be 890 // that for a construct call the constructor function in edi needs to be
918 // preserved for entering the generic code. In both cases argc in eax needs to 891 // preserved for entering the generic code. In both cases argc in eax needs to
919 // be preserved. 892 // be preserved.
920 static void ArrayNativeCode(MacroAssembler* masm, 893 static void ArrayNativeCode(MacroAssembler* masm,
921 bool construct_call, 894 bool construct_call,
922 Label* call_generic_code) { 895 Label* call_generic_code) {
923 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call; 896 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
897 empty_array, not_empty_array;
924 898
925 // Push the constructor and argc. No need to tag argc as a smi, as there will 899 // Push the constructor and argc. No need to tag argc as a smi, as there will
926 // be no garbage collection with this on the stack. 900 // be no garbage collection with this on the stack.
927 int push_count = 0; 901 int push_count = 0;
928 if (construct_call) { 902 if (construct_call) {
929 push_count++; 903 push_count++;
930 __ push(edi); 904 __ push(edi);
931 } 905 }
932 push_count++; 906 push_count++;
933 __ push(eax); 907 __ push(eax);
934 908
935 // Check for array construction with zero arguments. 909 // Check for array construction with zero arguments.
936 __ test(eax, Operand(eax)); 910 __ test(eax, Operand(eax));
937 __ j(not_zero, &argc_one_or_more); 911 __ j(not_zero, &argc_one_or_more);
938 912
913 __ bind(&empty_array);
939 // Handle construction of an empty array. 914 // Handle construction of an empty array.
940 AllocateEmptyJSArray(masm, 915 AllocateEmptyJSArray(masm,
941 edi, 916 edi,
942 eax, 917 eax,
943 ebx, 918 ebx,
944 ecx, 919 ecx,
945 edi, 920 edi,
946 kPreallocatedArrayElements, 921 kPreallocatedArrayElements,
947 &prepare_generic_code_call); 922 &prepare_generic_code_call);
948 __ IncrementCounter(&Counters::array_function_native, 1); 923 __ IncrementCounter(&Counters::array_function_native, 1);
949 __ pop(ebx); 924 __ pop(ebx);
950 if (construct_call) { 925 if (construct_call) {
951 __ pop(edi); 926 __ pop(edi);
952 } 927 }
953 __ ret(kPointerSize); 928 __ ret(kPointerSize);
954 929
955 // Check for one argument. Bail out if argument is not smi or if it is 930 // Check for one argument. Bail out if argument is not smi or if it is
956 // negative. 931 // negative.
957 __ bind(&argc_one_or_more); 932 __ bind(&argc_one_or_more);
958 __ cmp(eax, 1); 933 __ cmp(eax, 1);
959 __ j(not_equal, &argc_two_or_more); 934 __ j(not_equal, &argc_two_or_more);
960 ASSERT(kSmiTag == 0); 935 ASSERT(kSmiTag == 0);
961 __ test(Operand(esp, (push_count + 1) * kPointerSize), 936 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
962 Immediate(kIntptrSignBit | kSmiTagMask)); 937 __ test(ecx, Operand(ecx));
938 __ j(not_zero, &not_empty_array);
939
940 // Case above assumes there is only a single slot to drop in
941 // ret, but we have two.
942 for (int i = push_count; i >= 0; i--) {
943 __ mov(eax, Operand(esp, i * kPointerSize));
944 __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
945 }
946 __ add(Operand(esp), Immediate(kPointerSize));
947 __ jmp(&empty_array);
948
949 __ bind(&not_empty_array);
950 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
963 __ j(not_zero, &prepare_generic_code_call); 951 __ j(not_zero, &prepare_generic_code_call);
964 952
965 // Handle construction of an empty array of a certain size. Get the size from 953 // Handle construction of an empty array of a certain size. Get the size from
966 // the stack and bail out if size is to large to actually allocate an elements 954 // the stack and bail out if size is to large to actually allocate an elements
967 // array. 955 // array.
968 __ mov(edx, Operand(esp, (push_count + 1) * kPointerSize)); 956 __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
969 ASSERT(kSmiTag == 0);
970 __ cmp(edx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
971 __ j(greater_equal, &prepare_generic_code_call); 957 __ j(greater_equal, &prepare_generic_code_call);
972 958
973 // edx: array_size (smi) 959 // edx: array_size (smi)
974 // edi: constructor 960 // edi: constructor
975 // esp[0]: argc 961 // esp[0]: argc (cannot be 0 here)
976 // esp[4]: constructor (only if construct_call) 962 // esp[4]: constructor (only if construct_call)
977 // esp[8]: return address 963 // esp[8]: return address
978 // esp[C]: argument 964 // esp[C]: argument
979 AllocateJSArray(masm, 965 AllocateJSArray(masm,
980 edi, 966 edi,
981 edx, 967 ecx,
982 eax, 968 eax,
983 ebx, 969 ebx,
984 ecx, 970 edx,
985 edi, 971 edi,
986 true, 972 true,
987 &prepare_generic_code_call); 973 &prepare_generic_code_call);
988 __ IncrementCounter(&Counters::array_function_native, 1); 974 __ IncrementCounter(&Counters::array_function_native, 1);
989 __ pop(ebx); 975 __ pop(ebx);
990 if (construct_call) { 976 if (construct_call) {
991 __ pop(edi); 977 __ pop(edi);
992 } 978 }
993 __ ret(2 * kPointerSize); 979 __ ret(2 * kPointerSize);
994 980
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
1249 // Dont adapt arguments. 1235 // Dont adapt arguments.
1250 // ------------------------------------------- 1236 // -------------------------------------------
1251 __ bind(&dont_adapt_arguments); 1237 __ bind(&dont_adapt_arguments);
1252 __ jmp(Operand(edx)); 1238 __ jmp(Operand(edx));
1253 } 1239 }
1254 1240
1255 1241
1256 #undef __ 1242 #undef __
1257 1243
1258 } } // namespace v8::internal 1244 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ia32/assembler-ia32.cc ('k') | src/ia32/disasm-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698