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 (function(global, utils) { | 5 (function(global, utils) { |
6 | 6 |
7 "use strict"; | 7 "use strict"; |
8 | 8 |
9 %CheckIsBootstrapping(); | 9 %CheckIsBootstrapping(); |
10 | 10 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 var length = indices.length; | 59 var length = indices.length; |
60 for (var k = 0; k < length; ++k) { | 60 for (var k = 0; k < length; ++k) { |
61 var key = indices[k]; | 61 var key = indices[k]; |
62 if (!IS_UNDEFINED(key)) { | 62 if (!IS_UNDEFINED(key)) { |
63 var e = array[key]; | 63 var e = array[key]; |
64 if (!IS_UNDEFINED(e) || key in array) { | 64 if (!IS_UNDEFINED(e) || key in array) { |
65 keys.push(key); | 65 keys.push(key); |
66 } | 66 } |
67 } | 67 } |
68 } | 68 } |
69 %_CallFunction(keys, function(a, b) { return a - b; }, ArraySort); | 69 keys.sort(function(a, b) { return a - b; }); |
70 } | 70 } |
71 return keys; | 71 return keys; |
72 } | 72 } |
73 | 73 |
74 | 74 |
75 function SparseJoinWithSeparatorJS(array, len, convert, separator) { | 75 function SparseJoinWithSeparatorJS(array, len, convert, separator) { |
76 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); | 76 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); |
77 var totalLength = 0; | 77 var totalLength = 0; |
78 var elements = new InternalArray(keys.length * 2); | 78 var elements = new InternalArray(keys.length * 2); |
79 var previousKey = -1; | 79 var previousKey = -1; |
(...skipping 813 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
893 while (arguments_index < arguments_length) { | 893 while (arguments_index < arguments_length) { |
894 array[i++] = %_Arguments(arguments_index++); | 894 array[i++] = %_Arguments(arguments_index++); |
895 } | 895 } |
896 array.length = len - del_count + num_elements_to_add; | 896 array.length = len - del_count + num_elements_to_add; |
897 | 897 |
898 // Return the deleted elements. | 898 // Return the deleted elements. |
899 return deleted_elements; | 899 return deleted_elements; |
900 } | 900 } |
901 | 901 |
902 | 902 |
903 function InnerArraySort(length, comparefn) { | 903 function InnerArraySort(array, length, comparefn) { |
904 // In-place QuickSort algorithm. | 904 // In-place QuickSort algorithm. |
905 // For short (length <= 22) arrays, insertion sort is used for efficiency. | 905 // For short (length <= 22) arrays, insertion sort is used for efficiency. |
906 | 906 |
907 if (!IS_CALLABLE(comparefn)) { | 907 if (!IS_CALLABLE(comparefn)) { |
908 comparefn = function (x, y) { | 908 comparefn = function (x, y) { |
909 if (x === y) return 0; | 909 if (x === y) return 0; |
910 if (%_IsSmi(x) && %_IsSmi(y)) { | 910 if (%_IsSmi(x) && %_IsSmi(y)) { |
911 return %SmiLexicographicCompare(x, y); | 911 return %SmiLexicographicCompare(x, y); |
912 } | 912 } |
913 x = ToString(x); | 913 x = ToString(x); |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1138 obj[i] = UNDEFINED; | 1138 obj[i] = UNDEFINED; |
1139 } else { | 1139 } else { |
1140 delete obj[i]; | 1140 delete obj[i]; |
1141 } | 1141 } |
1142 } | 1142 } |
1143 | 1143 |
1144 // Return the number of defined elements. | 1144 // Return the number of defined elements. |
1145 return first_undefined; | 1145 return first_undefined; |
1146 }; | 1146 }; |
1147 | 1147 |
1148 if (length < 2) return this; | 1148 if (length < 2) return array; |
1149 | 1149 |
1150 var is_array = IS_ARRAY(this); | 1150 var is_array = IS_ARRAY(array); |
1151 var max_prototype_element; | 1151 var max_prototype_element; |
1152 if (!is_array) { | 1152 if (!is_array) { |
1153 // For compatibility with JSC, we also sort elements inherited from | 1153 // For compatibility with JSC, we also sort elements inherited from |
1154 // the prototype chain on non-Array objects. | 1154 // the prototype chain on non-Array objects. |
1155 // We do this by copying them to this object and sorting only | 1155 // We do this by copying them to this object and sorting only |
1156 // own elements. This is not very efficient, but sorting with | 1156 // own elements. This is not very efficient, but sorting with |
1157 // inherited elements happens very, very rarely, if at all. | 1157 // inherited elements happens very, very rarely, if at all. |
1158 // The specification allows "implementation dependent" behavior | 1158 // The specification allows "implementation dependent" behavior |
1159 // if an element on the prototype chain has an element that | 1159 // if an element on the prototype chain has an element that |
1160 // might interact with sorting. | 1160 // might interact with sorting. |
1161 max_prototype_element = CopyFromPrototype(this, length); | 1161 max_prototype_element = CopyFromPrototype(array, length); |
1162 } | 1162 } |
1163 | 1163 |
1164 // %RemoveArrayHoles returns -1 if fast removal is not supported. | 1164 // %RemoveArrayHoles returns -1 if fast removal is not supported. |
1165 var num_non_undefined = %RemoveArrayHoles(this, length); | 1165 var num_non_undefined = %RemoveArrayHoles(array, length); |
1166 | 1166 |
1167 if (num_non_undefined == -1) { | 1167 if (num_non_undefined == -1) { |
1168 // The array is observed, or there were indexed accessors in the array. | 1168 // The array is observed, or there were indexed accessors in the array. |
1169 // Move array holes and undefineds to the end using a Javascript function | 1169 // Move array holes and undefineds to the end using a Javascript function |
1170 // that is safe in the presence of accessors and is observable. | 1170 // that is safe in the presence of accessors and is observable. |
1171 num_non_undefined = SafeRemoveArrayHoles(this); | 1171 num_non_undefined = SafeRemoveArrayHoles(array); |
1172 } | 1172 } |
1173 | 1173 |
1174 QuickSort(this, 0, num_non_undefined); | 1174 QuickSort(array, 0, num_non_undefined); |
1175 | 1175 |
1176 if (!is_array && (num_non_undefined + 1 < max_prototype_element)) { | 1176 if (!is_array && (num_non_undefined + 1 < max_prototype_element)) { |
1177 // For compatibility with JSC, we shadow any elements in the prototype | 1177 // For compatibility with JSC, we shadow any elements in the prototype |
1178 // chain that has become exposed by sort moving a hole to its position. | 1178 // chain that has become exposed by sort moving a hole to its position. |
1179 ShadowPrototypeElements(this, num_non_undefined, max_prototype_element); | 1179 ShadowPrototypeElements(array, num_non_undefined, max_prototype_element); |
1180 } | 1180 } |
1181 | 1181 |
1182 return this; | 1182 return array; |
1183 } | 1183 } |
1184 | 1184 |
1185 | 1185 |
1186 function ArraySort(comparefn) { | 1186 function ArraySort(comparefn) { |
1187 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.sort"); | 1187 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.sort"); |
1188 | 1188 |
1189 var array = TO_OBJECT(this); | 1189 var array = TO_OBJECT(this); |
1190 var length = TO_UINT32(array.length); | 1190 var length = TO_UINT32(array.length); |
1191 return %_CallFunction(array, length, comparefn, InnerArraySort); | 1191 return InnerArraySort(array, length, comparefn); |
1192 } | 1192 } |
1193 | 1193 |
1194 | 1194 |
1195 // The following functions cannot be made efficient on sparse arrays while | 1195 // The following functions cannot be made efficient on sparse arrays while |
1196 // preserving the semantics, since the calls to the receiver function can add | 1196 // preserving the semantics, since the calls to the receiver function can add |
1197 // or delete elements from the array. | 1197 // or delete elements from the array. |
1198 function InnerArrayFilter(f, receiver, array, length) { | 1198 function InnerArrayFilter(f, receiver, array, length) { |
1199 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); | 1199 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); |
1200 var needs_wrapper = false; | 1200 var needs_wrapper = false; |
1201 if (IS_NULL(receiver)) { | 1201 if (IS_NULL(receiver)) { |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1375 var result = new GlobalArray(); | 1375 var result = new GlobalArray(); |
1376 %MoveArrayContents(accumulator, result); | 1376 %MoveArrayContents(accumulator, result); |
1377 return result; | 1377 return result; |
1378 } | 1378 } |
1379 | 1379 |
1380 | 1380 |
1381 // For .indexOf, we don't need to pass in the number of arguments | 1381 // For .indexOf, we don't need to pass in the number of arguments |
1382 // at the callsite since ToInteger(undefined) == 0; however, for | 1382 // at the callsite since ToInteger(undefined) == 0; however, for |
1383 // .lastIndexOf, we need to pass it, since the behavior for passing | 1383 // .lastIndexOf, we need to pass it, since the behavior for passing |
1384 // undefined is 0 but for not including the argument is length-1. | 1384 // undefined is 0 but for not including the argument is length-1. |
1385 function InnerArrayIndexOf(element, index, length) { | 1385 function InnerArrayIndexOf(array, element, index, length) { |
1386 if (length == 0) return -1; | 1386 if (length == 0) return -1; |
1387 if (IS_UNDEFINED(index)) { | 1387 if (IS_UNDEFINED(index)) { |
1388 index = 0; | 1388 index = 0; |
1389 } else { | 1389 } else { |
1390 index = TO_INTEGER(index); | 1390 index = TO_INTEGER(index); |
1391 // If index is negative, index from the end of the array. | 1391 // If index is negative, index from the end of the array. |
1392 if (index < 0) { | 1392 if (index < 0) { |
1393 index = length + index; | 1393 index = length + index; |
1394 // If index is still negative, search the entire array. | 1394 // If index is still negative, search the entire array. |
1395 if (index < 0) index = 0; | 1395 if (index < 0) index = 0; |
1396 } | 1396 } |
1397 } | 1397 } |
1398 var min = index; | 1398 var min = index; |
1399 var max = length; | 1399 var max = length; |
1400 if (UseSparseVariant(this, length, IS_ARRAY(this), max - min)) { | 1400 if (UseSparseVariant(array, length, IS_ARRAY(array), max - min)) { |
1401 %NormalizeElements(this); | 1401 %NormalizeElements(array); |
1402 var indices = %GetArrayKeys(this, length); | 1402 var indices = %GetArrayKeys(array, length); |
1403 if (IS_NUMBER(indices)) { | 1403 if (IS_NUMBER(indices)) { |
1404 // It's an interval. | 1404 // It's an interval. |
1405 max = indices; // Capped by length already. | 1405 max = indices; // Capped by length already. |
1406 // Fall through to loop below. | 1406 // Fall through to loop below. |
1407 } else { | 1407 } else { |
1408 if (indices.length == 0) return -1; | 1408 if (indices.length == 0) return -1; |
1409 // Get all the keys in sorted order. | 1409 // Get all the keys in sorted order. |
1410 var sortedKeys = GetSortedArrayKeys(this, indices); | 1410 var sortedKeys = GetSortedArrayKeys(array, indices); |
1411 var n = sortedKeys.length; | 1411 var n = sortedKeys.length; |
1412 var i = 0; | 1412 var i = 0; |
1413 while (i < n && sortedKeys[i] < index) i++; | 1413 while (i < n && sortedKeys[i] < index) i++; |
1414 while (i < n) { | 1414 while (i < n) { |
1415 var key = sortedKeys[i]; | 1415 var key = sortedKeys[i]; |
1416 if (!IS_UNDEFINED(key) && this[key] === element) return key; | 1416 if (!IS_UNDEFINED(key) && array[key] === element) return key; |
1417 i++; | 1417 i++; |
1418 } | 1418 } |
1419 return -1; | 1419 return -1; |
1420 } | 1420 } |
1421 } | 1421 } |
1422 // Lookup through the array. | 1422 // Lookup through the array. |
1423 if (!IS_UNDEFINED(element)) { | 1423 if (!IS_UNDEFINED(element)) { |
1424 for (var i = min; i < max; i++) { | 1424 for (var i = min; i < max; i++) { |
1425 if (this[i] === element) return i; | 1425 if (array[i] === element) return i; |
1426 } | 1426 } |
1427 return -1; | 1427 return -1; |
1428 } | 1428 } |
1429 // Lookup through the array. | 1429 // Lookup through the array. |
1430 for (var i = min; i < max; i++) { | 1430 for (var i = min; i < max; i++) { |
1431 if (IS_UNDEFINED(this[i]) && i in this) { | 1431 if (IS_UNDEFINED(array[i]) && i in array) { |
1432 return i; | 1432 return i; |
1433 } | 1433 } |
1434 } | 1434 } |
1435 return -1; | 1435 return -1; |
1436 } | 1436 } |
1437 | 1437 |
1438 | 1438 |
1439 function ArrayIndexOf(element, index) { | 1439 function ArrayIndexOf(element, index) { |
1440 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.indexOf"); | 1440 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.indexOf"); |
1441 | 1441 |
1442 var length = TO_UINT32(this.length); | 1442 var length = TO_UINT32(this.length); |
1443 return %_CallFunction(this, element, index, length, InnerArrayIndexOf); | 1443 return InnerArrayIndexOf(this, element, index, length); |
1444 } | 1444 } |
1445 | 1445 |
1446 | 1446 |
1447 function InnerArrayLastIndexOf(element, index, length, argumentsLength) { | 1447 function InnerArrayLastIndexOf(array, element, index, length, argumentsLength) { |
1448 if (length == 0) return -1; | 1448 if (length == 0) return -1; |
1449 if (argumentsLength < 2) { | 1449 if (argumentsLength < 2) { |
1450 index = length - 1; | 1450 index = length - 1; |
1451 } else { | 1451 } else { |
1452 index = TO_INTEGER(index); | 1452 index = TO_INTEGER(index); |
1453 // If index is negative, index from end of the array. | 1453 // If index is negative, index from end of the array. |
1454 if (index < 0) index += length; | 1454 if (index < 0) index += length; |
1455 // If index is still negative, do not search the array. | 1455 // If index is still negative, do not search the array. |
1456 if (index < 0) return -1; | 1456 if (index < 0) return -1; |
1457 else if (index >= length) index = length - 1; | 1457 else if (index >= length) index = length - 1; |
1458 } | 1458 } |
1459 var min = 0; | 1459 var min = 0; |
1460 var max = index; | 1460 var max = index; |
1461 if (UseSparseVariant(this, length, IS_ARRAY(this), index)) { | 1461 if (UseSparseVariant(array, length, IS_ARRAY(array), index)) { |
1462 %NormalizeElements(this); | 1462 %NormalizeElements(array); |
1463 var indices = %GetArrayKeys(this, index + 1); | 1463 var indices = %GetArrayKeys(array, index + 1); |
1464 if (IS_NUMBER(indices)) { | 1464 if (IS_NUMBER(indices)) { |
1465 // It's an interval. | 1465 // It's an interval. |
1466 max = indices; // Capped by index already. | 1466 max = indices; // Capped by index already. |
1467 // Fall through to loop below. | 1467 // Fall through to loop below. |
1468 } else { | 1468 } else { |
1469 if (indices.length == 0) return -1; | 1469 if (indices.length == 0) return -1; |
1470 // Get all the keys in sorted order. | 1470 // Get all the keys in sorted order. |
1471 var sortedKeys = GetSortedArrayKeys(this, indices); | 1471 var sortedKeys = GetSortedArrayKeys(array, indices); |
1472 var i = sortedKeys.length - 1; | 1472 var i = sortedKeys.length - 1; |
1473 while (i >= 0) { | 1473 while (i >= 0) { |
1474 var key = sortedKeys[i]; | 1474 var key = sortedKeys[i]; |
1475 if (!IS_UNDEFINED(key) && this[key] === element) return key; | 1475 if (!IS_UNDEFINED(key) && array[key] === element) return key; |
1476 i--; | 1476 i--; |
1477 } | 1477 } |
1478 return -1; | 1478 return -1; |
1479 } | 1479 } |
1480 } | 1480 } |
1481 // Lookup through the array. | 1481 // Lookup through the array. |
1482 if (!IS_UNDEFINED(element)) { | 1482 if (!IS_UNDEFINED(element)) { |
1483 for (var i = max; i >= min; i--) { | 1483 for (var i = max; i >= min; i--) { |
1484 if (this[i] === element) return i; | 1484 if (array[i] === element) return i; |
1485 } | 1485 } |
1486 return -1; | 1486 return -1; |
1487 } | 1487 } |
1488 for (var i = max; i >= min; i--) { | 1488 for (var i = max; i >= min; i--) { |
1489 if (IS_UNDEFINED(this[i]) && i in this) { | 1489 if (IS_UNDEFINED(array[i]) && i in array) { |
1490 return i; | 1490 return i; |
1491 } | 1491 } |
1492 } | 1492 } |
1493 return -1; | 1493 return -1; |
1494 } | 1494 } |
1495 | 1495 |
1496 | 1496 |
1497 function ArrayLastIndexOf(element, index) { | 1497 function ArrayLastIndexOf(element, index) { |
1498 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.lastIndexOf"); | 1498 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.lastIndexOf"); |
1499 | 1499 |
1500 var length = TO_UINT32(this.length); | 1500 var length = TO_UINT32(this.length); |
1501 return %_CallFunction(this, element, index, length, | 1501 return InnerArrayLastIndexOf(this, element, index, length, |
1502 %_ArgumentsLength(), InnerArrayLastIndexOf); | 1502 %_ArgumentsLength()); |
1503 } | 1503 } |
1504 | 1504 |
1505 | 1505 |
1506 function InnerArrayReduce(callback, current, array, length, argumentsLength) { | 1506 function InnerArrayReduce(callback, current, array, length, argumentsLength) { |
1507 if (!IS_CALLABLE(callback)) { | 1507 if (!IS_CALLABLE(callback)) { |
1508 throw MakeTypeError(kCalledNonCallable, callback); | 1508 throw MakeTypeError(kCalledNonCallable, callback); |
1509 } | 1509 } |
1510 | 1510 |
1511 var is_array = IS_ARRAY(array); | 1511 var is_array = IS_ARRAY(array); |
1512 var i = 0; | 1512 var i = 0; |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1665 // The internal Array prototype doesn't need to be fancy, since it's never | 1665 // The internal Array prototype doesn't need to be fancy, since it's never |
1666 // exposed to user code. | 1666 // exposed to user code. |
1667 // Adding only the functions that are actually used. | 1667 // Adding only the functions that are actually used. |
1668 utils.SetUpLockedPrototype(InternalArray, GlobalArray(), [ | 1668 utils.SetUpLockedPrototype(InternalArray, GlobalArray(), [ |
1669 "concat", getFunction("concat", ArrayConcatJS), | 1669 "concat", getFunction("concat", ArrayConcatJS), |
1670 "indexOf", getFunction("indexOf", ArrayIndexOf), | 1670 "indexOf", getFunction("indexOf", ArrayIndexOf), |
1671 "join", getFunction("join", ArrayJoin), | 1671 "join", getFunction("join", ArrayJoin), |
1672 "pop", getFunction("pop", ArrayPop), | 1672 "pop", getFunction("pop", ArrayPop), |
1673 "push", getFunction("push", ArrayPush), | 1673 "push", getFunction("push", ArrayPush), |
1674 "shift", getFunction("shift", ArrayShift), | 1674 "shift", getFunction("shift", ArrayShift), |
| 1675 "sort", getFunction("sort", ArraySort), |
1675 "splice", getFunction("splice", ArraySplice) | 1676 "splice", getFunction("splice", ArraySplice) |
1676 ]); | 1677 ]); |
1677 | 1678 |
1678 utils.SetUpLockedPrototype(InternalPackedArray, GlobalArray(), [ | 1679 utils.SetUpLockedPrototype(InternalPackedArray, GlobalArray(), [ |
1679 "join", getFunction("join", ArrayJoin), | 1680 "join", getFunction("join", ArrayJoin), |
1680 "pop", getFunction("pop", ArrayPop), | 1681 "pop", getFunction("pop", ArrayPop), |
1681 "push", getFunction("push", ArrayPush), | 1682 "push", getFunction("push", ArrayPush), |
1682 "shift", getFunction("shift", ArrayShift) | 1683 "shift", getFunction("shift", ArrayShift) |
1683 ]); | 1684 ]); |
1684 | 1685 |
(...skipping 24 matching lines...) Expand all Loading... |
1709 "array_concat", ArrayConcatJS, | 1710 "array_concat", ArrayConcatJS, |
1710 "array_pop", ArrayPop, | 1711 "array_pop", ArrayPop, |
1711 "array_push", ArrayPush, | 1712 "array_push", ArrayPush, |
1712 "array_shift", ArrayShift, | 1713 "array_shift", ArrayShift, |
1713 "array_splice", ArraySplice, | 1714 "array_splice", ArraySplice, |
1714 "array_slice", ArraySlice, | 1715 "array_slice", ArraySlice, |
1715 "array_unshift", ArrayUnshift, | 1716 "array_unshift", ArrayUnshift, |
1716 ]); | 1717 ]); |
1717 | 1718 |
1718 }); | 1719 }); |
OLD | NEW |