Chromium Code Reviews| 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 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 if (!IS_UNDEFINED(current) || key in array) { | 214 if (!IS_UNDEFINED(current) || key in array) { |
| 215 deleted_elements[key - start_i] = current; | 215 deleted_elements[key - start_i] = current; |
| 216 } | 216 } |
| 217 } | 217 } |
| 218 } | 218 } |
| 219 } | 219 } |
| 220 } | 220 } |
| 221 } | 221 } |
| 222 | 222 |
| 223 | 223 |
| 224 // This function implements the optimized splice implementation that can use | |
| 225 // special array operations to handle sparse arrays in a sensible fashion. | |
| 226 function SmartMove(array, start_i, del_count, len, num_additional_args) { | |
| 227 // Move data to new array. | |
| 228 var new_array = new InternalArray(len - del_count + num_additional_args); | |
| 229 var indices = %GetArrayKeys(array, len); | |
| 230 if (IS_NUMBER(indices)) { | |
| 231 var limit = indices; | |
| 232 for (var i = 0; i < start_i && i < limit; ++i) { | |
| 233 var current = array[i]; | |
| 234 if (!IS_UNDEFINED(current) || i in array) { | |
| 235 new_array[i] = current; | |
| 236 } | |
| 237 } | |
| 238 for (var i = start_i + del_count; i < limit; ++i) { | |
| 239 var current = array[i]; | |
| 240 if (!IS_UNDEFINED(current) || i in array) { | |
| 241 new_array[i - del_count + num_additional_args] = current; | |
| 242 } | |
| 243 } | |
| 244 } else { | |
| 245 var length = indices.length; | |
| 246 for (var k = 0; k < length; ++k) { | |
| 247 var key = indices[k]; | |
| 248 if (!IS_UNDEFINED(key)) { | |
| 249 if (key < start_i) { | |
| 250 var current = array[key]; | |
| 251 if (!IS_UNDEFINED(current) || key in array) { | |
| 252 new_array[key] = current; | |
| 253 } | |
| 254 } else if (key >= start_i + del_count) { | |
| 255 var current = array[key]; | |
| 256 if (!IS_UNDEFINED(current) || key in array) { | |
| 257 new_array[key - del_count + num_additional_args] = current; | |
| 258 } | |
| 259 } | |
| 260 } | |
| 261 } | |
| 262 } | |
| 263 // Move contents of new_array into this array | |
| 264 %MoveArrayContents(new_array, array); | |
| 265 } | |
| 266 | |
| 267 | |
| 268 // This is part of the old simple-minded splice. We are using it either | 224 // This is part of the old simple-minded splice. We are using it either |
| 269 // because the receiver is not an array (so we have no choice) or because we | 225 // because the receiver is not an array (so we have no choice) or because we |
| 270 // know we are not deleting or moving a lot of elements. | 226 // know we are not deleting or moving a lot of elements. |
| 271 function SimpleSlice(array, start_i, del_count, len, deleted_elements) { | 227 function SimpleSlice(array, start_i, del_count, len, deleted_elements) { |
| 272 for (var i = 0; i < del_count; i++) { | 228 for (var i = 0; i < del_count; i++) { |
| 273 var index = start_i + i; | 229 var index = start_i + i; |
| 274 // The spec could also be interpreted such that %HasOwnProperty | 230 // The spec could also be interpreted such that %HasOwnProperty |
| 275 // would be the appropriate test. We follow KJS in consulting the | 231 // would be the appropriate test. We follow KJS in consulting the |
| 276 // prototype. | 232 // prototype. |
| 277 var current = array[index]; | 233 var current = array[index]; |
| 278 if (!IS_UNDEFINED(current) || index in array) { | 234 if (!IS_UNDEFINED(current) || index in array) { |
| 279 deleted_elements[i] = current; | 235 deleted_elements[i] = current; |
| 280 } | 236 } |
| 281 } | 237 } |
| 282 } | 238 } |
| 283 | 239 |
| 284 | 240 |
| 285 function SimpleMove(array, start_i, del_count, len, num_additional_args) { | 241 function SimpleMove(array, start_i, del_count, len, num_additional_args, |
| 286 if (num_additional_args !== del_count) { | 242 force) { |
| 243 if (num_additional_args !== del_count || force) { | |
|
rafaelw
2014/06/22 23:59:18
Note that |force| is required here because the spe
| |
| 287 // Move the existing elements after the elements to be deleted | 244 // Move the existing elements after the elements to be deleted |
| 288 // to the right position in the resulting array. | 245 // to the right position in the resulting array. |
| 289 if (num_additional_args > del_count) { | 246 if (num_additional_args > del_count) { |
| 290 for (var i = len - del_count; i > start_i; i--) { | 247 for (var i = len - del_count; i > start_i; i--) { |
| 291 var from_index = i + del_count - 1; | 248 var from_index = i + del_count - 1; |
| 292 var to_index = i + num_additional_args - 1; | 249 var to_index = i + num_additional_args - 1; |
| 293 // The spec could also be interpreted such that | 250 // The spec could also be interpreted such that |
| 294 // %HasOwnProperty would be the appropriate test. We follow | 251 // %HasOwnProperty would be the appropriate test. We follow |
| 295 // KJS in consulting the prototype. | 252 // KJS in consulting the prototype. |
| 296 var current = array[from_index]; | 253 var current = array[from_index]; |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 579 if (ObjectIsSealed(array)) { | 536 if (ObjectIsSealed(array)) { |
| 580 throw MakeTypeError("array_functions_change_sealed", | 537 throw MakeTypeError("array_functions_change_sealed", |
| 581 ["Array.prototype.shift"]); | 538 ["Array.prototype.shift"]); |
| 582 } | 539 } |
| 583 | 540 |
| 584 if (%IsObserved(array)) | 541 if (%IsObserved(array)) |
| 585 return ObservedArrayShift.call(array, len); | 542 return ObservedArrayShift.call(array, len); |
| 586 | 543 |
| 587 var first = array[0]; | 544 var first = array[0]; |
| 588 | 545 |
| 589 if (IS_ARRAY(array)) { | 546 SimpleMove(array, 0, 1, len, 0); |
| 590 SmartMove(array, 0, 1, len, 0); | |
| 591 } else { | |
| 592 SimpleMove(array, 0, 1, len, 0); | |
| 593 } | |
| 594 | 547 |
| 595 array.length = len - 1; | 548 array.length = len - 1; |
| 596 | 549 |
| 597 return first; | 550 return first; |
| 598 } | 551 } |
| 599 | 552 |
| 600 function ObservedArrayUnshift() { | 553 function ObservedArrayUnshift() { |
| 601 var len = TO_UINT32(this.length); | 554 var len = TO_UINT32(this.length); |
| 602 var num_arguments = %_ArgumentsLength(); | 555 var num_arguments = %_ArgumentsLength(); |
| 603 | 556 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 619 | 572 |
| 620 function ArrayUnshift(arg1) { // length == 1 | 573 function ArrayUnshift(arg1) { // length == 1 |
| 621 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.unshift"); | 574 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.unshift"); |
| 622 | 575 |
| 623 if (%IsObserved(this)) | 576 if (%IsObserved(this)) |
| 624 return ObservedArrayUnshift.apply(this, arguments); | 577 return ObservedArrayUnshift.apply(this, arguments); |
| 625 | 578 |
| 626 var array = TO_OBJECT_INLINE(this); | 579 var array = TO_OBJECT_INLINE(this); |
| 627 var len = TO_UINT32(array.length); | 580 var len = TO_UINT32(array.length); |
| 628 var num_arguments = %_ArgumentsLength(); | 581 var num_arguments = %_ArgumentsLength(); |
| 629 var is_sealed = ObjectIsSealed(array); | 582 SimpleMove(array, 0, 0, len, num_arguments, true); |
| 630 | |
| 631 if (IS_ARRAY(array) && !is_sealed && len > 0) { | |
| 632 SmartMove(array, 0, 0, len, num_arguments); | |
| 633 } else { | |
| 634 SimpleMove(array, 0, 0, len, num_arguments); | |
| 635 } | |
| 636 | |
| 637 for (var i = 0; i < num_arguments; i++) { | 583 for (var i = 0; i < num_arguments; i++) { |
| 638 array[i] = %_Arguments(i); | 584 array[i] = %_Arguments(i); |
| 639 } | 585 } |
| 640 | 586 |
| 641 var new_length = len + num_arguments; | 587 var new_length = len + num_arguments; |
| 642 array.length = new_length; | 588 array.length = new_length; |
| 643 return new_length; | 589 return new_length; |
| 644 } | 590 } |
| 645 | 591 |
| 646 | 592 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 776 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; | 722 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; |
| 777 | 723 |
| 778 if (del_count != num_elements_to_add && ObjectIsSealed(array)) { | 724 if (del_count != num_elements_to_add && ObjectIsSealed(array)) { |
| 779 throw MakeTypeError("array_functions_change_sealed", | 725 throw MakeTypeError("array_functions_change_sealed", |
| 780 ["Array.prototype.splice"]); | 726 ["Array.prototype.splice"]); |
| 781 } else if (del_count > 0 && ObjectIsFrozen(array)) { | 727 } else if (del_count > 0 && ObjectIsFrozen(array)) { |
| 782 throw MakeTypeError("array_functions_on_frozen", | 728 throw MakeTypeError("array_functions_on_frozen", |
| 783 ["Array.prototype.splice"]); | 729 ["Array.prototype.splice"]); |
| 784 } | 730 } |
| 785 | 731 |
| 786 var use_simple_splice = true; | 732 SimpleSlice(array, start_i, del_count, len, deleted_elements); |
|
Toon Verwaest
2014/06/23 08:42:36
I guess now you can remove the "Simple" prefixes
| |
| 787 if (IS_ARRAY(array) && | 733 SimpleMove(array, start_i, del_count, len, num_elements_to_add); |
| 788 num_elements_to_add !== del_count) { | |
| 789 // If we are only deleting/moving a few things near the end of the | |
| 790 // array then the simple version is going to be faster, because it | |
| 791 // doesn't touch most of the array. | |
| 792 var estimated_non_hole_elements = %EstimateNumberOfElements(array); | |
| 793 if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) { | |
| 794 use_simple_splice = false; | |
| 795 } | |
| 796 } | |
| 797 | |
| 798 if (use_simple_splice) { | |
| 799 SimpleSlice(array, start_i, del_count, len, deleted_elements); | |
| 800 SimpleMove(array, start_i, del_count, len, num_elements_to_add); | |
| 801 } else { | |
| 802 SmartSlice(array, start_i, del_count, len, deleted_elements); | |
| 803 SmartMove(array, start_i, del_count, len, num_elements_to_add); | |
| 804 } | |
| 805 | 734 |
| 806 // Insert the arguments into the resulting array in | 735 // Insert the arguments into the resulting array in |
| 807 // place of the deleted elements. | 736 // place of the deleted elements. |
| 808 var i = start_i; | 737 var i = start_i; |
| 809 var arguments_index = 2; | 738 var arguments_index = 2; |
| 810 var arguments_length = %_ArgumentsLength(); | 739 var arguments_length = %_ArgumentsLength(); |
| 811 while (arguments_index < arguments_length) { | 740 while (arguments_index < arguments_length) { |
| 812 array[i++] = %_Arguments(arguments_index++); | 741 array[i++] = %_Arguments(arguments_index++); |
| 813 } | 742 } |
| 814 array.length = len - del_count + num_elements_to_add; | 743 array.length = len - del_count + num_elements_to_add; |
| (...skipping 710 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1525 )); | 1454 )); |
| 1526 | 1455 |
| 1527 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( | 1456 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( |
| 1528 "join", getFunction("join", ArrayJoin), | 1457 "join", getFunction("join", ArrayJoin), |
| 1529 "pop", getFunction("pop", ArrayPop), | 1458 "pop", getFunction("pop", ArrayPop), |
| 1530 "push", getFunction("push", ArrayPush) | 1459 "push", getFunction("push", ArrayPush) |
| 1531 )); | 1460 )); |
| 1532 } | 1461 } |
| 1533 | 1462 |
| 1534 SetUpArray(); | 1463 SetUpArray(); |
| OLD | NEW |