OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 "use strict"; | 5 "use strict"; |
6 | 6 |
7 // This file relies on the fact that the following declarations have been made | 7 // This file relies on the fact that the following declarations have been made |
8 // in runtime.js: | 8 // in runtime.js: |
9 // var $Array = global.Array; | 9 // var $Array = global.Array; |
10 | 10 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 var e = array[key]; | 79 var e = array[key]; |
80 if (!IS_STRING(e)) e = convert(e); | 80 if (!IS_STRING(e)) e = convert(e); |
81 elements[elements_length++] = e; | 81 elements[elements_length++] = e; |
82 last_key = key; | 82 last_key = key; |
83 } | 83 } |
84 } | 84 } |
85 return %StringBuilderConcat(elements, elements_length, ''); | 85 return %StringBuilderConcat(elements, elements_length, ''); |
86 } | 86 } |
87 | 87 |
88 | 88 |
89 function UseSparseVariant(object, length, is_array) { | 89 function UseSparseVariant(array, length, is_array, touched) { |
90 return is_array && | 90 // Only use the sparse variant on arrays that are likely to be sparse and the |
91 length > 1000 && | 91 // number of elements touched in the operation is relatively small compared to |
92 (!%_IsSmi(length) || | 92 // the overall size of the array. |
93 %EstimateNumberOfElements(object) < (length >> 2)); | 93 if (!is_array || length < 1000 || %IsObserved(array)) { |
| 94 return false; |
| 95 } |
| 96 if (!%_IsSmi(length)) { |
| 97 return true; |
| 98 } |
| 99 var elements_threshold = length >> 2; // No more than 75% holes |
| 100 var estimated_elements = %EstimateNumberOfElements(array); |
| 101 return (estimated_elements < elements_threshold) && |
| 102 (touched > estimated_elements * 4); |
94 } | 103 } |
95 | 104 |
96 | 105 |
97 function Join(array, length, separator, convert) { | 106 function Join(array, length, separator, convert) { |
98 if (length == 0) return ''; | 107 if (length == 0) return ''; |
99 | 108 |
100 var is_array = IS_ARRAY(array); | 109 var is_array = IS_ARRAY(array); |
101 | 110 |
102 if (is_array) { | 111 if (is_array) { |
103 // If the array is cyclic, return the empty string for already | 112 // If the array is cyclic, return the empty string for already |
104 // visited arrays. | 113 // visited arrays. |
105 if (!%PushIfAbsent(visited_arrays, array)) return ''; | 114 if (!%PushIfAbsent(visited_arrays, array)) return ''; |
106 } | 115 } |
107 | 116 |
108 // Attempt to convert the elements. | 117 // Attempt to convert the elements. |
109 try { | 118 try { |
110 if (UseSparseVariant(array, length, is_array)) { | 119 if (UseSparseVariant(array, length, is_array, length)) { |
| 120 %NormalizeElements(array); |
111 if (separator.length == 0) { | 121 if (separator.length == 0) { |
112 return SparseJoin(array, length, convert); | 122 return SparseJoin(array, length, convert); |
113 } else { | 123 } else { |
114 return SparseJoinWithSeparatorJS(array, length, convert, separator); | 124 return SparseJoinWithSeparatorJS(array, length, convert, separator); |
115 } | 125 } |
116 } | 126 } |
117 | 127 |
118 // Fast case for one-element arrays. | 128 // Fast case for one-element arrays. |
119 if (length == 1) { | 129 if (length == 1) { |
120 var e = array[0]; | 130 var e = array[0]; |
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 } | 521 } |
512 } | 522 } |
513 } | 523 } |
514 } | 524 } |
515 | 525 |
516 | 526 |
517 function ArrayReverse() { | 527 function ArrayReverse() { |
518 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reverse"); | 528 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reverse"); |
519 | 529 |
520 var array = TO_OBJECT_INLINE(this); | 530 var array = TO_OBJECT_INLINE(this); |
521 var j = TO_UINT32(array.length) - 1; | 531 var len = TO_UINT32(array.length); |
522 | 532 |
523 if (UseSparseVariant(array, j, IS_ARRAY(array))) { | 533 if (UseSparseVariant(array, len, IS_ARRAY(array), len)) { |
524 SparseReverse(array, j+1); | 534 %NormalizeElements(array); |
| 535 SparseReverse(array, len); |
525 return array; | 536 return array; |
526 } | 537 } |
527 | 538 |
| 539 var j = len - 1; |
528 for (var i = 0; i < j; i++, j--) { | 540 for (var i = 0; i < j; i++, j--) { |
529 var current_i = array[i]; | 541 var current_i = array[i]; |
530 if (!IS_UNDEFINED(current_i) || i in array) { | 542 if (!IS_UNDEFINED(current_i) || i in array) { |
531 var current_j = array[j]; | 543 var current_j = array[j]; |
532 if (!IS_UNDEFINED(current_j) || j in array) { | 544 if (!IS_UNDEFINED(current_j) || j in array) { |
533 array[i] = current_j; | 545 array[i] = current_j; |
534 array[j] = current_i; | 546 array[j] = current_i; |
535 } else { | 547 } else { |
536 array[j] = current_i; | 548 array[j] = current_i; |
537 delete array[i]; | 549 delete array[i]; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
663 end_i += len; | 675 end_i += len; |
664 if (end_i < 0) end_i = 0; | 676 if (end_i < 0) end_i = 0; |
665 } else { | 677 } else { |
666 if (end_i > len) end_i = len; | 678 if (end_i > len) end_i = len; |
667 } | 679 } |
668 | 680 |
669 var result = []; | 681 var result = []; |
670 | 682 |
671 if (end_i < start_i) return result; | 683 if (end_i < start_i) return result; |
672 | 684 |
673 if (IS_ARRAY(array) && | 685 if (UseSparseVariant(array, len, IS_ARRAY(array), end_i - start_i)) { |
674 !%IsObserved(array) && | 686 %NormalizeElements(array); |
675 (end_i > 1000) && | 687 %NormalizeElements(result); |
676 (%EstimateNumberOfElements(array) < end_i)) { | |
677 SmartSlice(array, start_i, end_i - start_i, len, result); | 688 SmartSlice(array, start_i, end_i - start_i, len, result); |
678 } else { | 689 } else { |
679 SimpleSlice(array, start_i, end_i - start_i, len, result); | 690 SimpleSlice(array, start_i, end_i - start_i, len, result); |
680 } | 691 } |
681 | 692 |
682 result.length = end_i - start_i; | 693 result.length = end_i - start_i; |
683 | 694 |
684 return result; | 695 return result; |
685 } | 696 } |
686 | 697 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; | 785 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; |
775 | 786 |
776 if (del_count != num_elements_to_add && ObjectIsSealed(array)) { | 787 if (del_count != num_elements_to_add && ObjectIsSealed(array)) { |
777 throw MakeTypeError("array_functions_change_sealed", | 788 throw MakeTypeError("array_functions_change_sealed", |
778 ["Array.prototype.splice"]); | 789 ["Array.prototype.splice"]); |
779 } else if (del_count > 0 && ObjectIsFrozen(array)) { | 790 } else if (del_count > 0 && ObjectIsFrozen(array)) { |
780 throw MakeTypeError("array_functions_on_frozen", | 791 throw MakeTypeError("array_functions_on_frozen", |
781 ["Array.prototype.splice"]); | 792 ["Array.prototype.splice"]); |
782 } | 793 } |
783 | 794 |
784 var use_simple_splice = true; | 795 var changed_elements = del_count; |
785 if (IS_ARRAY(array) && | 796 if (num_elements_to_add != del_count) { |
786 num_elements_to_add !== del_count) { | 797 // If the slice needs to do a actually move elements after the insertion |
787 // If we are only deleting/moving a few things near the end of the | 798 // point, then include those in the estimate of changed elements. |
788 // array then the simple version is going to be faster, because it | 799 changed_elements += len - start_i - del_count; |
789 // doesn't touch most of the array. | |
790 var estimated_non_hole_elements = %EstimateNumberOfElements(array); | |
791 if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) { | |
792 use_simple_splice = false; | |
793 } | |
794 } | 800 } |
795 | 801 if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) { |
796 if (use_simple_splice) { | 802 %NormalizeElements(array); |
| 803 %NormalizeElements(deleted_elements); |
| 804 SmartSlice(array, start_i, del_count, len, deleted_elements); |
| 805 SmartMove(array, start_i, del_count, len, num_elements_to_add); |
| 806 } else { |
797 SimpleSlice(array, start_i, del_count, len, deleted_elements); | 807 SimpleSlice(array, start_i, del_count, len, deleted_elements); |
798 SimpleMove(array, start_i, del_count, len, num_elements_to_add); | 808 SimpleMove(array, start_i, del_count, len, num_elements_to_add); |
799 } else { | |
800 SmartSlice(array, start_i, del_count, len, deleted_elements); | |
801 SmartMove(array, start_i, del_count, len, num_elements_to_add); | |
802 } | 809 } |
803 | 810 |
804 // Insert the arguments into the resulting array in | 811 // Insert the arguments into the resulting array in |
805 // place of the deleted elements. | 812 // place of the deleted elements. |
806 var i = start_i; | 813 var i = start_i; |
807 var arguments_index = 2; | 814 var arguments_index = 2; |
808 var arguments_length = %_ArgumentsLength(); | 815 var arguments_length = %_ArgumentsLength(); |
809 while (arguments_index < arguments_length) { | 816 while (arguments_index < arguments_length) { |
810 array[i++] = %_Arguments(arguments_index++); | 817 array[i++] = %_Arguments(arguments_index++); |
811 } | 818 } |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1276 index = TO_INTEGER(index); | 1283 index = TO_INTEGER(index); |
1277 // If index is negative, index from the end of the array. | 1284 // If index is negative, index from the end of the array. |
1278 if (index < 0) { | 1285 if (index < 0) { |
1279 index = length + index; | 1286 index = length + index; |
1280 // If index is still negative, search the entire array. | 1287 // If index is still negative, search the entire array. |
1281 if (index < 0) index = 0; | 1288 if (index < 0) index = 0; |
1282 } | 1289 } |
1283 } | 1290 } |
1284 var min = index; | 1291 var min = index; |
1285 var max = length; | 1292 var max = length; |
1286 if (UseSparseVariant(this, length, IS_ARRAY(this))) { | 1293 if (UseSparseVariant(this, length, IS_ARRAY(this), max - min)) { |
| 1294 %NormalizeElements(this); |
1287 var indices = %GetArrayKeys(this, length); | 1295 var indices = %GetArrayKeys(this, length); |
1288 if (IS_NUMBER(indices)) { | 1296 if (IS_NUMBER(indices)) { |
1289 // It's an interval. | 1297 // It's an interval. |
1290 max = indices; // Capped by length already. | 1298 max = indices; // Capped by length already. |
1291 // Fall through to loop below. | 1299 // Fall through to loop below. |
1292 } else { | 1300 } else { |
1293 if (indices.length == 0) return -1; | 1301 if (indices.length == 0) return -1; |
1294 // Get all the keys in sorted order. | 1302 // Get all the keys in sorted order. |
1295 var sortedKeys = GetSortedArrayKeys(this, indices); | 1303 var sortedKeys = GetSortedArrayKeys(this, indices); |
1296 var n = sortedKeys.length; | 1304 var n = sortedKeys.length; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1331 } else { | 1339 } else { |
1332 index = TO_INTEGER(index); | 1340 index = TO_INTEGER(index); |
1333 // If index is negative, index from end of the array. | 1341 // If index is negative, index from end of the array. |
1334 if (index < 0) index += length; | 1342 if (index < 0) index += length; |
1335 // If index is still negative, do not search the array. | 1343 // If index is still negative, do not search the array. |
1336 if (index < 0) return -1; | 1344 if (index < 0) return -1; |
1337 else if (index >= length) index = length - 1; | 1345 else if (index >= length) index = length - 1; |
1338 } | 1346 } |
1339 var min = 0; | 1347 var min = 0; |
1340 var max = index; | 1348 var max = index; |
1341 if (UseSparseVariant(this, length, IS_ARRAY(this))) { | 1349 if (UseSparseVariant(this, length, IS_ARRAY(this), index)) { |
| 1350 %NormalizeElements(this); |
1342 var indices = %GetArrayKeys(this, index + 1); | 1351 var indices = %GetArrayKeys(this, index + 1); |
1343 if (IS_NUMBER(indices)) { | 1352 if (IS_NUMBER(indices)) { |
1344 // It's an interval. | 1353 // It's an interval. |
1345 max = indices; // Capped by index already. | 1354 max = indices; // Capped by index already. |
1346 // Fall through to loop below. | 1355 // Fall through to loop below. |
1347 } else { | 1356 } else { |
1348 if (indices.length == 0) return -1; | 1357 if (indices.length == 0) return -1; |
1349 // Get all the keys in sorted order. | 1358 // Get all the keys in sorted order. |
1350 var sortedKeys = GetSortedArrayKeys(this, indices); | 1359 var sortedKeys = GetSortedArrayKeys(this, indices); |
1351 var i = sortedKeys.length - 1; | 1360 var i = sortedKeys.length - 1; |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1523 )); | 1532 )); |
1524 | 1533 |
1525 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( | 1534 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( |
1526 "join", getFunction("join", ArrayJoin), | 1535 "join", getFunction("join", ArrayJoin), |
1527 "pop", getFunction("pop", ArrayPop), | 1536 "pop", getFunction("pop", ArrayPop), |
1528 "push", getFunction("push", ArrayPush) | 1537 "push", getFunction("push", ArrayPush) |
1529 )); | 1538 )); |
1530 } | 1539 } |
1531 | 1540 |
1532 SetUpArray(); | 1541 SetUpArray(); |
OLD | NEW |