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 |