| 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 |