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, extrasUtils) { | 5 (function(global, utils, extrasUtils) { |
6 | 6 |
7 "use strict"; | 7 "use strict"; |
8 | 8 |
9 %CheckIsBootstrapping(); | 9 %CheckIsBootstrapping(); |
10 | 10 |
11 // ------------------------------------------------------------------- | 11 // ------------------------------------------------------------------- |
12 // Imports | 12 // Imports |
13 | 13 |
14 var FLAG_harmony_species; | 14 var FLAG_harmony_species; |
15 var GetIterator; | 15 var GetIterator; |
16 var GetMethod; | 16 var GetMethod; |
17 var GlobalArray = global.Array; | 17 var GlobalArray = global.Array; |
18 var InternalArray = utils.InternalArray; | 18 var InternalArray = utils.InternalArray; |
19 var InternalPackedArray = utils.InternalPackedArray; | 19 var InternalPackedArray = utils.InternalPackedArray; |
20 var MakeTypeError; | 20 var MakeTypeError; |
21 var MaxSimple; | 21 var MaxSimple; |
22 var MinSimple; | 22 var MinSimple; |
23 var ObjectDefineProperty; | 23 var ObjectDefineProperty; |
24 var ObjectHasOwnProperty; | 24 var ObjectHasOwnProperty; |
25 var ObjectToString = utils.ImportNow("object_to_string"); | 25 var ObjectToString = utils.ImportNow("object_to_string"); |
26 var ObserveBeginPerformSplice; | |
27 var ObserveEndPerformSplice; | |
28 var ObserveEnqueueSpliceRecord; | |
29 var iteratorSymbol = utils.ImportNow("iterator_symbol"); | 26 var iteratorSymbol = utils.ImportNow("iterator_symbol"); |
30 var unscopablesSymbol = utils.ImportNow("unscopables_symbol"); | 27 var unscopablesSymbol = utils.ImportNow("unscopables_symbol"); |
31 | 28 |
32 utils.Import(function(from) { | 29 utils.Import(function(from) { |
33 GetIterator = from.GetIterator; | 30 GetIterator = from.GetIterator; |
34 GetMethod = from.GetMethod; | 31 GetMethod = from.GetMethod; |
35 MakeTypeError = from.MakeTypeError; | 32 MakeTypeError = from.MakeTypeError; |
36 MaxSimple = from.MaxSimple; | 33 MaxSimple = from.MaxSimple; |
37 MinSimple = from.MinSimple; | 34 MinSimple = from.MinSimple; |
38 ObjectDefineProperty = from.ObjectDefineProperty; | 35 ObjectDefineProperty = from.ObjectDefineProperty; |
39 ObjectHasOwnProperty = from.ObjectHasOwnProperty; | 36 ObjectHasOwnProperty = from.ObjectHasOwnProperty; |
40 ObserveBeginPerformSplice = from.ObserveBeginPerformSplice; | |
41 ObserveEndPerformSplice = from.ObserveEndPerformSplice; | |
42 ObserveEnqueueSpliceRecord = from.ObserveEnqueueSpliceRecord; | |
43 }); | 37 }); |
44 | 38 |
45 utils.ImportFromExperimental(function(from) { | 39 utils.ImportFromExperimental(function(from) { |
46 FLAG_harmony_species = from.FLAG_harmony_species; | 40 FLAG_harmony_species = from.FLAG_harmony_species; |
47 }); | 41 }); |
48 | 42 |
49 // ------------------------------------------------------------------- | 43 // ------------------------------------------------------------------- |
50 | 44 |
51 | 45 |
52 function ArraySpeciesCreate(array, length) { | 46 function ArraySpeciesCreate(array, length) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 elements[i] = IS_STRING(e) ? e : convert(e); | 97 elements[i] = IS_STRING(e) ? e : convert(e); |
104 } | 98 } |
105 return %StringBuilderConcat(elements, keys_length, ''); | 99 return %StringBuilderConcat(elements, keys_length, ''); |
106 } | 100 } |
107 | 101 |
108 | 102 |
109 function UseSparseVariant(array, length, is_array, touched) { | 103 function UseSparseVariant(array, length, is_array, touched) { |
110 // Only use the sparse variant on arrays that are likely to be sparse and the | 104 // Only use the sparse variant on arrays that are likely to be sparse and the |
111 // number of elements touched in the operation is relatively small compared to | 105 // number of elements touched in the operation is relatively small compared to |
112 // the overall size of the array. | 106 // the overall size of the array. |
113 if (!is_array || length < 1000 || %IsObserved(array) || | 107 if (!is_array || length < 1000 || %HasComplexElements(array)) { |
114 %HasComplexElements(array)) { | |
115 return false; | 108 return false; |
116 } | 109 } |
117 if (!%_IsSmi(length)) { | 110 if (!%_IsSmi(length)) { |
118 return true; | 111 return true; |
119 } | 112 } |
120 var elements_threshold = length >> 2; // No more than 75% holes | 113 var elements_threshold = length >> 2; // No more than 75% holes |
121 var estimated_elements = %EstimateNumberOfElements(array); | 114 var estimated_elements = %EstimateNumberOfElements(array); |
122 return (estimated_elements < elements_threshold) && | 115 return (estimated_elements < elements_threshold) && |
123 (touched > estimated_elements * 4); | 116 (touched > estimated_elements * 4); |
124 } | 117 } |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 function ArrayJoin(separator) { | 429 function ArrayJoin(separator) { |
437 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.join"); | 430 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.join"); |
438 | 431 |
439 var array = TO_OBJECT(this); | 432 var array = TO_OBJECT(this); |
440 var length = TO_LENGTH(array.length); | 433 var length = TO_LENGTH(array.length); |
441 | 434 |
442 return InnerArrayJoin(separator, array, length); | 435 return InnerArrayJoin(separator, array, length); |
443 } | 436 } |
444 | 437 |
445 | 438 |
446 function ObservedArrayPop(n) { | |
447 n--; | |
448 var value = this[n]; | |
449 | |
450 try { | |
451 ObserveBeginPerformSplice(this); | |
452 delete this[n]; | |
453 this.length = n; | |
454 } finally { | |
455 ObserveEndPerformSplice(this); | |
456 ObserveEnqueueSpliceRecord(this, n, [value], 0); | |
457 } | |
458 | |
459 return value; | |
460 } | |
461 | |
462 | |
463 // Removes the last element from the array and returns it. See | 439 // Removes the last element from the array and returns it. See |
464 // ECMA-262, section 15.4.4.6. | 440 // ECMA-262, section 15.4.4.6. |
465 function ArrayPop() { | 441 function ArrayPop() { |
466 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.pop"); | 442 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.pop"); |
467 | 443 |
468 var array = TO_OBJECT(this); | 444 var array = TO_OBJECT(this); |
469 var n = TO_LENGTH(array.length); | 445 var n = TO_LENGTH(array.length); |
470 if (n == 0) { | 446 if (n == 0) { |
471 array.length = n; | 447 array.length = n; |
472 return; | 448 return; |
473 } | 449 } |
474 | 450 |
475 if (%IsObserved(array)) | |
476 return ObservedArrayPop.call(array, n); | |
477 | |
478 n--; | 451 n--; |
479 var value = array[n]; | 452 var value = array[n]; |
480 %DeleteProperty_Strict(array, n); | 453 %DeleteProperty_Strict(array, n); |
481 array.length = n; | 454 array.length = n; |
482 return value; | 455 return value; |
483 } | 456 } |
484 | 457 |
485 | 458 |
486 function ObservedArrayPush() { | |
487 var n = TO_LENGTH(this.length); | |
488 var m = arguments.length; | |
489 | |
490 try { | |
491 ObserveBeginPerformSplice(this); | |
492 for (var i = 0; i < m; i++) { | |
493 this[i+n] = arguments[i]; | |
494 } | |
495 var new_length = n + m; | |
496 this.length = new_length; | |
497 } finally { | |
498 ObserveEndPerformSplice(this); | |
499 ObserveEnqueueSpliceRecord(this, n, [], m); | |
500 } | |
501 | |
502 return new_length; | |
503 } | |
504 | |
505 | |
506 // Appends the arguments to the end of the array and returns the new | 459 // Appends the arguments to the end of the array and returns the new |
507 // length of the array. See ECMA-262, section 15.4.4.7. | 460 // length of the array. See ECMA-262, section 15.4.4.7. |
508 function ArrayPush() { | 461 function ArrayPush() { |
509 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push"); | 462 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push"); |
510 | 463 |
511 if (%IsObserved(this)) | |
512 return ObservedArrayPush.apply(this, arguments); | |
513 | |
514 var array = TO_OBJECT(this); | 464 var array = TO_OBJECT(this); |
515 var n = TO_LENGTH(array.length); | 465 var n = TO_LENGTH(array.length); |
516 var m = arguments.length; | 466 var m = arguments.length; |
517 | 467 |
518 // It appears that there is no enforced, absolute limit on the number of | 468 // It appears that there is no enforced, absolute limit on the number of |
519 // arguments, but it would surely blow the stack to use 2**30 or more. | 469 // arguments, but it would surely blow the stack to use 2**30 or more. |
520 // To avoid integer overflow, do the comparison to the max safe integer | 470 // To avoid integer overflow, do the comparison to the max safe integer |
521 // after subtracting 2**30 from both sides. (2**31 would seem like a | 471 // after subtracting 2**30 from both sides. (2**31 would seem like a |
522 // natural value, but it is negative in JS, and 2**32 is 1.) | 472 // natural value, but it is negative in JS, and 2**32 is 1.) |
523 if (m > (1 << 30) || (n - (1 << 30)) + m > kMaxSafeInteger - (1 << 30)) { | 473 if (m > (1 << 30) || (n - (1 << 30)) + m > kMaxSafeInteger - (1 << 30)) { |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
626 SparseReverse(array, len); | 576 SparseReverse(array, len); |
627 return array; | 577 return array; |
628 } else if (isArray && %_HasFastPackedElements(array)) { | 578 } else if (isArray && %_HasFastPackedElements(array)) { |
629 return PackedArrayReverse(array, len); | 579 return PackedArrayReverse(array, len); |
630 } else { | 580 } else { |
631 return GenericArrayReverse(array, len); | 581 return GenericArrayReverse(array, len); |
632 } | 582 } |
633 } | 583 } |
634 | 584 |
635 | 585 |
636 function ObservedArrayShift(len) { | |
637 var first = this[0]; | |
638 | |
639 try { | |
640 ObserveBeginPerformSplice(this); | |
641 SimpleMove(this, 0, 1, len, 0); | |
642 this.length = len - 1; | |
643 } finally { | |
644 ObserveEndPerformSplice(this); | |
645 ObserveEnqueueSpliceRecord(this, 0, [first], 0); | |
646 } | |
647 | |
648 return first; | |
649 } | |
650 | |
651 | |
652 function ArrayShift() { | 586 function ArrayShift() { |
653 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.shift"); | 587 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.shift"); |
654 | 588 |
655 var array = TO_OBJECT(this); | 589 var array = TO_OBJECT(this); |
656 var len = TO_LENGTH(array.length); | 590 var len = TO_LENGTH(array.length); |
657 | 591 |
658 if (len === 0) { | 592 if (len === 0) { |
659 array.length = 0; | 593 array.length = 0; |
660 return; | 594 return; |
661 } | 595 } |
662 | 596 |
663 if (%object_is_sealed(array)) throw MakeTypeError(kArrayFunctionsOnSealed); | 597 if (%object_is_sealed(array)) throw MakeTypeError(kArrayFunctionsOnSealed); |
664 | 598 |
665 if (%IsObserved(array)) | |
666 return ObservedArrayShift.call(array, len); | |
667 | |
668 var first = array[0]; | 599 var first = array[0]; |
669 | 600 |
670 if (UseSparseVariant(array, len, IS_ARRAY(array), len)) { | 601 if (UseSparseVariant(array, len, IS_ARRAY(array), len)) { |
671 SparseMove(array, 0, 1, len, 0); | 602 SparseMove(array, 0, 1, len, 0); |
672 } else { | 603 } else { |
673 SimpleMove(array, 0, 1, len, 0); | 604 SimpleMove(array, 0, 1, len, 0); |
674 } | 605 } |
675 | 606 |
676 array.length = len - 1; | 607 array.length = len - 1; |
677 | 608 |
678 return first; | 609 return first; |
679 } | 610 } |
680 | 611 |
681 | 612 |
682 function ObservedArrayUnshift() { | |
683 var len = TO_LENGTH(this.length); | |
684 var num_arguments = arguments.length; | |
685 | |
686 try { | |
687 ObserveBeginPerformSplice(this); | |
688 SimpleMove(this, 0, 0, len, num_arguments); | |
689 for (var i = 0; i < num_arguments; i++) { | |
690 this[i] = arguments[i]; | |
691 } | |
692 var new_length = len + num_arguments; | |
693 this.length = new_length; | |
694 } finally { | |
695 ObserveEndPerformSplice(this); | |
696 ObserveEnqueueSpliceRecord(this, 0, [], num_arguments); | |
697 } | |
698 | |
699 return new_length; | |
700 } | |
701 | |
702 | |
703 function ArrayUnshift(arg1) { // length == 1 | 613 function ArrayUnshift(arg1) { // length == 1 |
704 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.unshift"); | 614 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.unshift"); |
705 | 615 |
706 if (%IsObserved(this)) | |
707 return ObservedArrayUnshift.apply(this, arguments); | |
708 | |
709 var array = TO_OBJECT(this); | 616 var array = TO_OBJECT(this); |
710 var len = TO_LENGTH(array.length); | 617 var len = TO_LENGTH(array.length); |
711 var num_arguments = arguments.length; | 618 var num_arguments = arguments.length; |
712 | 619 |
713 if (len > 0 && UseSparseVariant(array, len, IS_ARRAY(array), len) && | 620 if (len > 0 && UseSparseVariant(array, len, IS_ARRAY(array), len) && |
714 !%object_is_sealed(array)) { | 621 !%object_is_sealed(array)) { |
715 SparseMove(array, 0, 0, len, num_arguments); | 622 SparseMove(array, 0, 0, len, num_arguments); |
716 } else { | 623 } else { |
717 SimpleMove(array, 0, 0, len, num_arguments); | 624 SimpleMove(array, 0, 0, len, num_arguments); |
718 } | 625 } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
793 if (del_count < 0) | 700 if (del_count < 0) |
794 return 0; | 701 return 0; |
795 | 702 |
796 if (del_count > len - start_i) | 703 if (del_count > len - start_i) |
797 return len - start_i; | 704 return len - start_i; |
798 | 705 |
799 return del_count; | 706 return del_count; |
800 } | 707 } |
801 | 708 |
802 | 709 |
803 function ObservedArraySplice(start, delete_count) { | |
804 var num_arguments = arguments.length; | |
805 var len = TO_LENGTH(this.length); | |
806 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len); | |
807 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len, | |
808 start_i); | |
809 var deleted_elements = []; | |
810 deleted_elements.length = del_count; | |
811 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; | |
812 | |
813 try { | |
814 ObserveBeginPerformSplice(this); | |
815 | |
816 SimpleSlice(this, start_i, del_count, len, deleted_elements); | |
817 SimpleMove(this, start_i, del_count, len, num_elements_to_add); | |
818 | |
819 // Insert the arguments into the resulting array in | |
820 // place of the deleted elements. | |
821 var i = start_i; | |
822 var arguments_index = 2; | |
823 var arguments_length = arguments.length; | |
824 while (arguments_index < arguments_length) { | |
825 this[i++] = arguments[arguments_index++]; | |
826 } | |
827 this.length = len - del_count + num_elements_to_add; | |
828 | |
829 } finally { | |
830 ObserveEndPerformSplice(this); | |
831 if (deleted_elements.length || num_elements_to_add) { | |
832 ObserveEnqueueSpliceRecord(this, | |
833 start_i, | |
834 deleted_elements.slice(), | |
835 num_elements_to_add); | |
836 } | |
837 } | |
838 | |
839 // Return the deleted elements. | |
840 return deleted_elements; | |
841 } | |
842 | |
843 | |
844 function ArraySplice(start, delete_count) { | 710 function ArraySplice(start, delete_count) { |
845 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.splice"); | 711 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.splice"); |
846 | 712 |
847 if (%IsObserved(this)) | |
848 return ObservedArraySplice.apply(this, arguments); | |
849 | |
850 var num_arguments = arguments.length; | 713 var num_arguments = arguments.length; |
851 var array = TO_OBJECT(this); | 714 var array = TO_OBJECT(this); |
852 var len = TO_LENGTH(array.length); | 715 var len = TO_LENGTH(array.length); |
853 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len); | 716 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len); |
854 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len, | 717 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len, |
855 start_i); | 718 start_i); |
856 var deleted_elements = ArraySpeciesCreate(array, del_count); | 719 var deleted_elements = ArraySpeciesCreate(array, del_count); |
857 deleted_elements.length = del_count; | 720 deleted_elements.length = del_count; |
858 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; | 721 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; |
859 | 722 |
(...skipping 1071 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1931 %InstallToContext([ | 1794 %InstallToContext([ |
1932 "array_pop", ArrayPop, | 1795 "array_pop", ArrayPop, |
1933 "array_push", ArrayPush, | 1796 "array_push", ArrayPush, |
1934 "array_shift", ArrayShift, | 1797 "array_shift", ArrayShift, |
1935 "array_splice", ArraySplice, | 1798 "array_splice", ArraySplice, |
1936 "array_slice", ArraySlice, | 1799 "array_slice", ArraySlice, |
1937 "array_unshift", ArrayUnshift, | 1800 "array_unshift", ArrayUnshift, |
1938 ]); | 1801 ]); |
1939 | 1802 |
1940 }); | 1803 }); |
OLD | NEW |