| 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 |