OLD | NEW |
1 // Copyright 2011 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 |
11 // with the distribution. | 11 // with the distribution. |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 | 186 |
187 static MaybeObject* ArrayCodeGenericCommon(Arguments* args, | 187 static MaybeObject* ArrayCodeGenericCommon(Arguments* args, |
188 Isolate* isolate, | 188 Isolate* isolate, |
189 JSFunction* constructor) { | 189 JSFunction* constructor) { |
190 Heap* heap = isolate->heap(); | 190 Heap* heap = isolate->heap(); |
191 isolate->counters()->array_function_runtime()->Increment(); | 191 isolate->counters()->array_function_runtime()->Increment(); |
192 | 192 |
193 JSArray* array; | 193 JSArray* array; |
194 if (CalledAsConstructor(isolate)) { | 194 if (CalledAsConstructor(isolate)) { |
195 array = JSArray::cast((*args)[0]); | 195 array = JSArray::cast((*args)[0]); |
| 196 // Initialize elements and length in case later allocations fail so that the |
| 197 // array object is initialized in a valid state. |
| 198 array->set_length(Smi::FromInt(0)); |
| 199 array->set_elements(heap->empty_fixed_array()); |
| 200 if (!FLAG_smi_only_arrays) { |
| 201 if (array->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS) { |
| 202 Context* global_context = isolate->context()->global_context(); |
| 203 array->set_map(Map::cast(global_context->object_js_array_map())); |
| 204 } |
| 205 } |
196 } else { | 206 } else { |
197 // Allocate the JS Array | 207 // Allocate the JS Array |
198 Object* obj; | 208 MaybeObject* maybe_obj = |
199 { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor); | 209 heap->AllocateEmptyJSArray(FAST_SMI_ONLY_ELEMENTS); |
200 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 210 if (!maybe_obj->To(&array)) return maybe_obj; |
201 } | |
202 array = JSArray::cast(obj); | |
203 } | 211 } |
204 | 212 |
205 // Optimize the case where there is one argument and the argument is a | 213 // Optimize the case where there is one argument and the argument is a |
206 // small smi. | 214 // small smi. |
207 if (args->length() == 2) { | 215 if (args->length() == 2) { |
208 Object* obj = (*args)[1]; | 216 Object* obj = (*args)[1]; |
209 if (obj->IsSmi()) { | 217 if (obj->IsSmi()) { |
210 int len = Smi::cast(obj)->value(); | 218 int len = Smi::cast(obj)->value(); |
211 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) { | 219 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) { |
212 Object* obj; | 220 Object* obj; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 | 302 |
295 | 303 |
296 BUILTIN(ArrayCodeGeneric) { | 304 BUILTIN(ArrayCodeGeneric) { |
297 return ArrayCodeGenericCommon( | 305 return ArrayCodeGenericCommon( |
298 &args, | 306 &args, |
299 isolate, | 307 isolate, |
300 isolate->context()->global_context()->array_function()); | 308 isolate->context()->global_context()->array_function()); |
301 } | 309 } |
302 | 310 |
303 | 311 |
304 MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) { | |
305 JSFunction* array_function = | |
306 heap->isolate()->context()->global_context()->array_function(); | |
307 Object* result; | |
308 { MaybeObject* maybe_result = heap->AllocateJSObject(array_function); | |
309 if (!maybe_result->ToObject(&result)) return maybe_result; | |
310 } | |
311 return result; | |
312 } | |
313 | |
314 | |
315 MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray(Heap* heap) { | |
316 Object* result; | |
317 { MaybeObject* maybe_result = AllocateJSArray(heap); | |
318 if (!maybe_result->ToObject(&result)) return maybe_result; | |
319 } | |
320 JSArray* result_array = JSArray::cast(result); | |
321 result_array->set_length(Smi::FromInt(0)); | |
322 result_array->set_elements(heap->empty_fixed_array()); | |
323 return result_array; | |
324 } | |
325 | |
326 | |
327 static void CopyElements(Heap* heap, | 312 static void CopyElements(Heap* heap, |
328 AssertNoAllocation* no_gc, | 313 AssertNoAllocation* no_gc, |
329 FixedArray* dst, | 314 FixedArray* dst, |
330 int dst_index, | 315 int dst_index, |
331 FixedArray* src, | 316 FixedArray* src, |
332 int src_index, | 317 int src_index, |
333 int len) { | 318 int len) { |
| 319 if (len == 0) return; |
334 ASSERT(dst != src); // Use MoveElements instead. | 320 ASSERT(dst != src); // Use MoveElements instead. |
335 ASSERT(dst->map() != HEAP->fixed_cow_array_map()); | 321 ASSERT(dst->map() != HEAP->fixed_cow_array_map()); |
336 ASSERT(len > 0); | 322 ASSERT(len > 0); |
337 CopyWords(dst->data_start() + dst_index, | 323 CopyWords(dst->data_start() + dst_index, |
338 src->data_start() + src_index, | 324 src->data_start() + src_index, |
339 len); | 325 len); |
340 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); | 326 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); |
341 if (mode == UPDATE_WRITE_BARRIER) { | 327 if (mode == UPDATE_WRITE_BARRIER) { |
342 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); | 328 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); |
343 } | 329 } |
344 heap->incremental_marking()->RecordWrites(dst); | 330 heap->incremental_marking()->RecordWrites(dst); |
345 } | 331 } |
346 | 332 |
347 | 333 |
348 static void MoveElements(Heap* heap, | 334 static void MoveElements(Heap* heap, |
349 AssertNoAllocation* no_gc, | 335 AssertNoAllocation* no_gc, |
350 FixedArray* dst, | 336 FixedArray* dst, |
351 int dst_index, | 337 int dst_index, |
352 FixedArray* src, | 338 FixedArray* src, |
353 int src_index, | 339 int src_index, |
354 int len) { | 340 int len) { |
| 341 if (len == 0) return; |
355 ASSERT(dst->map() != HEAP->fixed_cow_array_map()); | 342 ASSERT(dst->map() != HEAP->fixed_cow_array_map()); |
356 memmove(dst->data_start() + dst_index, | 343 memmove(dst->data_start() + dst_index, |
357 src->data_start() + src_index, | 344 src->data_start() + src_index, |
358 len * kPointerSize); | 345 len * kPointerSize); |
359 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); | 346 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); |
360 if (mode == UPDATE_WRITE_BARRIER) { | 347 if (mode == UPDATE_WRITE_BARRIER) { |
361 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); | 348 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); |
362 } | 349 } |
363 heap->incremental_marking()->RecordWrites(dst); | 350 heap->incremental_marking()->RecordWrites(dst); |
364 } | 351 } |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 if (new_length > elms->length()) { | 523 if (new_length > elms->length()) { |
537 // New backing storage is needed. | 524 // New backing storage is needed. |
538 int capacity = new_length + (new_length >> 1) + 16; | 525 int capacity = new_length + (new_length >> 1) + 16; |
539 Object* obj; | 526 Object* obj; |
540 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); | 527 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); |
541 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 528 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
542 } | 529 } |
543 FixedArray* new_elms = FixedArray::cast(obj); | 530 FixedArray* new_elms = FixedArray::cast(obj); |
544 | 531 |
545 AssertNoAllocation no_gc; | 532 AssertNoAllocation no_gc; |
546 if (len > 0) { | 533 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len); |
547 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len); | |
548 } | |
549 FillWithHoles(heap, new_elms, new_length, capacity); | 534 FillWithHoles(heap, new_elms, new_length, capacity); |
550 | 535 |
551 elms = new_elms; | 536 elms = new_elms; |
552 } | 537 } |
553 | 538 |
554 // Add the provided values. | 539 // Add the provided values. |
555 AssertNoAllocation no_gc; | 540 AssertNoAllocation no_gc; |
556 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); | 541 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); |
557 for (int index = 0; index < to_add; index++) { | 542 for (int index = 0; index < to_add; index++) { |
558 elms->set(index + len, args[index + 1], mode); | 543 elms->set(index + len, args[index + 1], mode); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 | 659 |
675 if (new_length > elms->length()) { | 660 if (new_length > elms->length()) { |
676 // New backing storage is needed. | 661 // New backing storage is needed. |
677 int capacity = new_length + (new_length >> 1) + 16; | 662 int capacity = new_length + (new_length >> 1) + 16; |
678 Object* obj; | 663 Object* obj; |
679 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); | 664 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); |
680 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 665 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
681 } | 666 } |
682 FixedArray* new_elms = FixedArray::cast(obj); | 667 FixedArray* new_elms = FixedArray::cast(obj); |
683 AssertNoAllocation no_gc; | 668 AssertNoAllocation no_gc; |
684 if (len > 0) { | 669 CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len); |
685 CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len); | |
686 } | |
687 FillWithHoles(heap, new_elms, new_length, capacity); | 670 FillWithHoles(heap, new_elms, new_length, capacity); |
688 elms = new_elms; | 671 elms = new_elms; |
689 array->set_elements(elms); | 672 array->set_elements(elms); |
690 } else { | 673 } else { |
691 AssertNoAllocation no_gc; | 674 AssertNoAllocation no_gc; |
692 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len); | 675 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len); |
693 } | 676 } |
694 | 677 |
695 // Add the provided values. | 678 // Add the provided values. |
696 AssertNoAllocation no_gc; | 679 AssertNoAllocation no_gc; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 } | 757 } |
775 | 758 |
776 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. | 759 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. |
777 int k = (relative_start < 0) ? Max(len + relative_start, 0) | 760 int k = (relative_start < 0) ? Max(len + relative_start, 0) |
778 : Min(relative_start, len); | 761 : Min(relative_start, len); |
779 | 762 |
780 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. | 763 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. |
781 int final = (relative_end < 0) ? Max(len + relative_end, 0) | 764 int final = (relative_end < 0) ? Max(len + relative_end, 0) |
782 : Min(relative_end, len); | 765 : Min(relative_end, len); |
783 | 766 |
| 767 ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind(); |
| 768 |
784 // Calculate the length of result array. | 769 // Calculate the length of result array. |
785 int result_len = final - k; | 770 int result_len = Max(final - k, 0); |
786 if (result_len <= 0) { | |
787 return AllocateEmptyJSArray(heap); | |
788 } | |
789 | 771 |
790 Object* result; | 772 MaybeObject* maybe_array = |
791 { MaybeObject* maybe_result = AllocateJSArray(heap); | 773 heap->AllocateJSArrayAndStorage(elements_kind, |
792 if (!maybe_result->ToObject(&result)) return maybe_result; | 774 result_len, |
793 } | 775 result_len); |
794 JSArray* result_array = JSArray::cast(result); | 776 JSArray* result_array; |
795 | 777 if (!maybe_array->To(&result_array)) return maybe_array; |
796 { MaybeObject* maybe_result = | |
797 heap->AllocateUninitializedFixedArray(result_len); | |
798 if (!maybe_result->ToObject(&result)) return maybe_result; | |
799 } | |
800 FixedArray* result_elms = FixedArray::cast(result); | |
801 | |
802 MaybeObject* maybe_object = | |
803 result_array->EnsureCanContainElements(result_elms, | |
804 DONT_ALLOW_DOUBLE_ELEMENTS); | |
805 if (maybe_object->IsFailure()) return maybe_object; | |
806 | 778 |
807 AssertNoAllocation no_gc; | 779 AssertNoAllocation no_gc; |
808 CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len); | 780 CopyElements(heap, &no_gc, FixedArray::cast(result_array->elements()), 0, |
| 781 elms, k, result_len); |
809 | 782 |
810 // Set elements. | |
811 result_array->set_elements(result_elms); | |
812 | |
813 // Set the length. | |
814 result_array->set_length(Smi::FromInt(result_len)); | |
815 | |
816 // Set the ElementsKind. | |
817 ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind(); | |
818 if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(), | |
819 elements_kind)) { | |
820 MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind); | |
821 if (maybe->IsFailure()) return maybe; | |
822 } | |
823 return result_array; | 783 return result_array; |
824 } | 784 } |
825 | 785 |
826 | 786 |
827 BUILTIN(ArraySplice) { | 787 BUILTIN(ArraySplice) { |
828 Heap* heap = isolate->heap(); | 788 Heap* heap = isolate->heap(); |
829 Object* receiver = *args.receiver(); | 789 Object* receiver = *args.receiver(); |
830 Object* elms_obj; | 790 Object* elms_obj; |
831 { MaybeObject* maybe_elms_obj = | 791 { MaybeObject* maybe_elms_obj = |
832 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3); | 792 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 if (arg2->IsSmi()) { | 833 if (arg2->IsSmi()) { |
874 value = Smi::cast(arg2)->value(); | 834 value = Smi::cast(arg2)->value(); |
875 } else { | 835 } else { |
876 return CallJsBuiltin(isolate, "ArraySplice", args); | 836 return CallJsBuiltin(isolate, "ArraySplice", args); |
877 } | 837 } |
878 } | 838 } |
879 actual_delete_count = Min(Max(value, 0), len - actual_start); | 839 actual_delete_count = Min(Max(value, 0), len - actual_start); |
880 } | 840 } |
881 | 841 |
882 JSArray* result_array = NULL; | 842 JSArray* result_array = NULL; |
883 if (actual_delete_count == 0) { | 843 ElementsKind elements_kind = |
884 Object* result; | 844 JSObject::cast(receiver)->GetElementsKind(); |
885 { MaybeObject* maybe_result = AllocateEmptyJSArray(heap); | 845 MaybeObject* maybe_array = |
886 if (!maybe_result->ToObject(&result)) return maybe_result; | 846 heap->AllocateJSArrayAndStorage(elements_kind, |
887 } | 847 actual_delete_count, |
888 result_array = JSArray::cast(result); | 848 actual_delete_count); |
889 } else { | 849 if (!maybe_array->To(&result_array)) return maybe_array; |
890 // Allocate result array. | |
891 Object* result; | |
892 { MaybeObject* maybe_result = AllocateJSArray(heap); | |
893 if (!maybe_result->ToObject(&result)) return maybe_result; | |
894 } | |
895 result_array = JSArray::cast(result); | |
896 | 850 |
897 { MaybeObject* maybe_result = | 851 { |
898 heap->AllocateUninitializedFixedArray(actual_delete_count); | |
899 if (!maybe_result->ToObject(&result)) return maybe_result; | |
900 } | |
901 FixedArray* result_elms = FixedArray::cast(result); | |
902 | |
903 AssertNoAllocation no_gc; | 852 AssertNoAllocation no_gc; |
904 // Fill newly created array. | 853 // Fill newly created array. |
905 CopyElements(heap, | 854 CopyElements(heap, |
906 &no_gc, | 855 &no_gc, |
907 result_elms, 0, | 856 FixedArray::cast(result_array->elements()), 0, |
908 elms, actual_start, | 857 elms, actual_start, |
909 actual_delete_count); | 858 actual_delete_count); |
910 | |
911 // Set elements. | |
912 result_array->set_elements(result_elms); | |
913 | |
914 // Set the length. | |
915 result_array->set_length(Smi::FromInt(actual_delete_count)); | |
916 | |
917 // Set the ElementsKind. | |
918 ElementsKind elements_kind = array->GetElementsKind(); | |
919 if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(), | |
920 elements_kind)) { | |
921 MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind); | |
922 if (maybe->IsFailure()) return maybe; | |
923 } | |
924 } | 859 } |
925 | 860 |
926 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; | 861 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; |
927 int new_length = len - actual_delete_count + item_count; | 862 int new_length = len - actual_delete_count + item_count; |
928 | 863 |
929 bool elms_changed = false; | 864 bool elms_changed = false; |
930 if (item_count < actual_delete_count) { | 865 if (item_count < actual_delete_count) { |
931 // Shrink the array. | 866 // Shrink the array. |
932 const bool trim_array = !heap->lo_space()->Contains(elms) && | 867 const bool trim_array = !heap->lo_space()->Contains(elms) && |
933 ((actual_start + item_count) < | 868 ((actual_start + item_count) < |
934 (len - actual_delete_count - actual_start)); | 869 (len - actual_delete_count - actual_start)); |
935 if (trim_array) { | 870 if (trim_array) { |
936 const int delta = actual_delete_count - item_count; | 871 const int delta = actual_delete_count - item_count; |
937 | 872 |
938 if (actual_start > 0) { | 873 { |
939 AssertNoAllocation no_gc; | 874 AssertNoAllocation no_gc; |
940 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start); | 875 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start); |
941 } | 876 } |
942 | 877 |
943 elms = LeftTrimFixedArray(heap, elms, delta); | 878 elms = LeftTrimFixedArray(heap, elms, delta); |
944 | 879 |
945 elms_changed = true; | 880 elms_changed = true; |
946 } else { | 881 } else { |
947 AssertNoAllocation no_gc; | 882 AssertNoAllocation no_gc; |
948 MoveElements(heap, &no_gc, | 883 MoveElements(heap, &no_gc, |
(...skipping 11 matching lines...) Expand all Loading... |
960 if (new_length > elms->length()) { | 895 if (new_length > elms->length()) { |
961 // New backing storage is needed. | 896 // New backing storage is needed. |
962 int capacity = new_length + (new_length >> 1) + 16; | 897 int capacity = new_length + (new_length >> 1) + 16; |
963 Object* obj; | 898 Object* obj; |
964 { MaybeObject* maybe_obj = | 899 { MaybeObject* maybe_obj = |
965 heap->AllocateUninitializedFixedArray(capacity); | 900 heap->AllocateUninitializedFixedArray(capacity); |
966 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 901 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
967 } | 902 } |
968 FixedArray* new_elms = FixedArray::cast(obj); | 903 FixedArray* new_elms = FixedArray::cast(obj); |
969 | 904 |
970 AssertNoAllocation no_gc; | 905 { |
971 // Copy the part before actual_start as is. | 906 AssertNoAllocation no_gc; |
972 if (actual_start > 0) { | 907 // Copy the part before actual_start as is. |
973 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start); | 908 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start); |
974 } | 909 const int to_copy = len - actual_delete_count - actual_start; |
975 const int to_copy = len - actual_delete_count - actual_start; | |
976 if (to_copy > 0) { | |
977 CopyElements(heap, &no_gc, | 910 CopyElements(heap, &no_gc, |
978 new_elms, actual_start + item_count, | 911 new_elms, actual_start + item_count, |
979 elms, actual_start + actual_delete_count, | 912 elms, actual_start + actual_delete_count, |
980 to_copy); | 913 to_copy); |
981 } | 914 } |
| 915 |
982 FillWithHoles(heap, new_elms, new_length, capacity); | 916 FillWithHoles(heap, new_elms, new_length, capacity); |
983 | 917 |
984 elms = new_elms; | 918 elms = new_elms; |
985 elms_changed = true; | 919 elms_changed = true; |
986 } else { | 920 } else { |
987 AssertNoAllocation no_gc; | 921 AssertNoAllocation no_gc; |
988 MoveElements(heap, &no_gc, | 922 MoveElements(heap, &no_gc, |
989 elms, actual_start + item_count, | 923 elms, actual_start + item_count, |
990 elms, actual_start + actual_delete_count, | 924 elms, actual_start + actual_delete_count, |
991 (len - actual_delete_count - actual_start)); | 925 (len - actual_delete_count - actual_start)); |
(...skipping 23 matching lines...) Expand all Loading... |
1015 JSObject* array_proto = | 949 JSObject* array_proto = |
1016 JSObject::cast(global_context->array_function()->prototype()); | 950 JSObject::cast(global_context->array_function()->prototype()); |
1017 if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) { | 951 if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) { |
1018 return CallJsBuiltin(isolate, "ArrayConcat", args); | 952 return CallJsBuiltin(isolate, "ArrayConcat", args); |
1019 } | 953 } |
1020 | 954 |
1021 // Iterate through all the arguments performing checks | 955 // Iterate through all the arguments performing checks |
1022 // and calculating total length. | 956 // and calculating total length. |
1023 int n_arguments = args.length(); | 957 int n_arguments = args.length(); |
1024 int result_len = 0; | 958 int result_len = 0; |
| 959 ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS; |
1025 for (int i = 0; i < n_arguments; i++) { | 960 for (int i = 0; i < n_arguments; i++) { |
1026 Object* arg = args[i]; | 961 Object* arg = args[i]; |
1027 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastTypeElements() | 962 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastTypeElements() |
1028 || JSArray::cast(arg)->GetPrototype() != array_proto) { | 963 || JSArray::cast(arg)->GetPrototype() != array_proto) { |
1029 return CallJsBuiltin(isolate, "ArrayConcat", args); | 964 return CallJsBuiltin(isolate, "ArrayConcat", args); |
1030 } | 965 } |
1031 | 966 |
1032 int len = Smi::cast(JSArray::cast(arg)->length())->value(); | 967 int len = Smi::cast(JSArray::cast(arg)->length())->value(); |
1033 | 968 |
1034 // We shouldn't overflow when adding another len. | 969 // We shouldn't overflow when adding another len. |
1035 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | 970 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
1036 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); | 971 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
1037 USE(kHalfOfMaxInt); | 972 USE(kHalfOfMaxInt); |
1038 result_len += len; | 973 result_len += len; |
1039 ASSERT(result_len >= 0); | 974 ASSERT(result_len >= 0); |
1040 | 975 |
1041 if (result_len > FixedArray::kMaxLength) { | 976 if (result_len > FixedArray::kMaxLength) { |
1042 return CallJsBuiltin(isolate, "ArrayConcat", args); | 977 return CallJsBuiltin(isolate, "ArrayConcat", args); |
1043 } | 978 } |
1044 } | |
1045 | 979 |
1046 if (result_len == 0) { | 980 if (!JSArray::cast(arg)->HasFastElements()) { |
1047 return AllocateEmptyJSArray(heap); | 981 elements_kind = FAST_ELEMENTS; |
| 982 } |
1048 } | 983 } |
1049 | 984 |
1050 // Allocate result. | 985 // Allocate result. |
1051 Object* result; | 986 JSArray* result_array; |
1052 { MaybeObject* maybe_result = AllocateJSArray(heap); | 987 MaybeObject* maybe_array = |
1053 if (!maybe_result->ToObject(&result)) return maybe_result; | 988 heap->AllocateJSArrayAndStorage(elements_kind, |
1054 } | 989 result_len, |
1055 JSArray* result_array = JSArray::cast(result); | 990 result_len); |
1056 | 991 if (!maybe_array->To(&result_array)) return maybe_array; |
1057 { MaybeObject* maybe_result = | 992 if (result_len == 0) return result_array; |
1058 heap->AllocateUninitializedFixedArray(result_len); | |
1059 if (!maybe_result->ToObject(&result)) return maybe_result; | |
1060 } | |
1061 FixedArray* result_elms = FixedArray::cast(result); | |
1062 | |
1063 // Ensure element type transitions happen before copying elements in. | |
1064 if (result_array->HasFastSmiOnlyElements()) { | |
1065 for (int i = 0; i < n_arguments; i++) { | |
1066 JSArray* array = JSArray::cast(args[i]); | |
1067 if (!array->HasFastSmiOnlyElements()) { | |
1068 result_array->EnsureCanContainHeapObjectElements(); | |
1069 break; | |
1070 } | |
1071 } | |
1072 } | |
1073 | 993 |
1074 // Copy data. | 994 // Copy data. |
1075 AssertNoAllocation no_gc; | 995 AssertNoAllocation no_gc; |
1076 int start_pos = 0; | 996 int start_pos = 0; |
| 997 FixedArray* result_elms(FixedArray::cast(result_array->elements())); |
1077 for (int i = 0; i < n_arguments; i++) { | 998 for (int i = 0; i < n_arguments; i++) { |
1078 JSArray* array = JSArray::cast(args[i]); | 999 JSArray* array = JSArray::cast(args[i]); |
1079 int len = Smi::cast(array->length())->value(); | 1000 int len = Smi::cast(array->length())->value(); |
1080 if (len > 0) { | 1001 FixedArray* elms = FixedArray::cast(array->elements()); |
1081 FixedArray* elms = FixedArray::cast(array->elements()); | 1002 CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len); |
1082 CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len); | 1003 start_pos += len; |
1083 start_pos += len; | |
1084 } | |
1085 } | 1004 } |
1086 ASSERT(start_pos == result_len); | 1005 ASSERT(start_pos == result_len); |
1087 | 1006 |
1088 // Set the length and elements. | |
1089 result_array->set_length(Smi::FromInt(result_len)); | |
1090 result_array->set_elements(result_elms); | |
1091 | |
1092 return result_array; | 1007 return result_array; |
1093 } | 1008 } |
1094 | 1009 |
1095 | 1010 |
1096 // ----------------------------------------------------------------------------- | 1011 // ----------------------------------------------------------------------------- |
1097 // Strict mode poison pills | 1012 // Strict mode poison pills |
1098 | 1013 |
1099 | 1014 |
1100 BUILTIN(StrictModePoisonPill) { | 1015 BUILTIN(StrictModePoisonPill) { |
1101 HandleScope scope; | 1016 HandleScope scope; |
(...skipping 726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1828 return Handle<Code>(code_address); \ | 1743 return Handle<Code>(code_address); \ |
1829 } | 1744 } |
1830 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 1745 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) |
1831 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 1746 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) |
1832 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 1747 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
1833 #undef DEFINE_BUILTIN_ACCESSOR_C | 1748 #undef DEFINE_BUILTIN_ACCESSOR_C |
1834 #undef DEFINE_BUILTIN_ACCESSOR_A | 1749 #undef DEFINE_BUILTIN_ACCESSOR_A |
1835 | 1750 |
1836 | 1751 |
1837 } } // namespace v8::internal | 1752 } } // namespace v8::internal |
OLD | NEW |