OLD | NEW |
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 Loading... |
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, ¬_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(¬_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, ¬_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(¬_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, ¬_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(¬_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 Loading... |
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 |
OLD | NEW |