| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 separator = NonStringToString(separator); | 388 separator = NonStringToString(separator); |
| 389 } | 389 } |
| 390 | 390 |
| 391 var result = %_FastAsciiArrayJoin(this, separator); | 391 var result = %_FastAsciiArrayJoin(this, separator); |
| 392 if (!IS_UNDEFINED(result)) return result; | 392 if (!IS_UNDEFINED(result)) return result; |
| 393 | 393 |
| 394 return Join(this, length, separator, ConvertToString); | 394 return Join(this, length, separator, ConvertToString); |
| 395 } | 395 } |
| 396 | 396 |
| 397 | 397 |
| 398 function ObservedArrayPop(n) { | |
| 399 n--; | |
| 400 var value = this[n]; | |
| 401 | |
| 402 EnqueueSpliceRecord(this, n, [value], 1, 0); | |
| 403 | |
| 404 try { | |
| 405 BeginPerformSplice(this); | |
| 406 delete this[n]; | |
| 407 this.length = n; | |
| 408 } finally { | |
| 409 EndPerformSplice(this); | |
| 410 } | |
| 411 | |
| 412 return value; | |
| 413 } | |
| 414 | |
| 415 // Removes the last element from the array and returns it. See | 398 // Removes the last element from the array and returns it. See |
| 416 // ECMA-262, section 15.4.4.6. | 399 // ECMA-262, section 15.4.4.6. |
| 417 function ArrayPop() { | 400 function ArrayPop() { |
| 418 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 401 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
| 419 throw MakeTypeError("called_on_null_or_undefined", | 402 throw MakeTypeError("called_on_null_or_undefined", |
| 420 ["Array.prototype.pop"]); | 403 ["Array.prototype.pop"]); |
| 421 } | 404 } |
| 422 | 405 |
| 423 var n = TO_UINT32(this.length); | 406 var n = TO_UINT32(this.length); |
| 424 if (n == 0) { | 407 if (n == 0) { |
| 425 this.length = n; | 408 this.length = n; |
| 426 return; | 409 return; |
| 427 } | 410 } |
| 428 | |
| 429 if (%IsObserved(this)) | |
| 430 return ObservedArrayPop.call(this, n); | |
| 431 | |
| 432 n--; | 411 n--; |
| 433 var value = this[n]; | 412 var value = this[n]; |
| 434 delete this[n]; | 413 delete this[n]; |
| 435 this.length = n; | 414 this.length = n; |
| 436 return value; | 415 return value; |
| 437 } | 416 } |
| 438 | 417 |
| 439 | 418 |
| 440 function ObservedArrayPush() { | 419 function ObservedArrayPush() { |
| 441 var n = TO_UINT32(this.length); | 420 var n = TO_UINT32(this.length); |
| 442 var m = %_ArgumentsLength(); | 421 var m = %_ArgumentsLength(); |
| 443 | 422 |
| 444 EnqueueSpliceRecord(this, n, [], 0, m); | 423 EnqueueSpliceRecord(this, n, [], 0, m); |
| 445 | 424 |
| 446 try { | 425 try { |
| 447 BeginPerformSplice(this); | 426 BeginPerformSplice(this); |
| 427 |
| 448 for (var i = 0; i < m; i++) { | 428 for (var i = 0; i < m; i++) { |
| 449 this[i+n] = %_Arguments(i); | 429 this[i+n] = %_Arguments(i); |
| 450 } | 430 } |
| 451 this.length = n + m; | 431 this.length = n + m; |
| 452 } finally { | 432 } finally { |
| 453 EndPerformSplice(this); | 433 EndPerformSplice(this); |
| 454 } | 434 } |
| 455 | 435 |
| 456 return this.length; | 436 return this.length; |
| 457 } | 437 } |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 571 if (!IS_UNDEFINED(current_j) || j in this) { | 551 if (!IS_UNDEFINED(current_j) || j in this) { |
| 572 this[i] = current_j; | 552 this[i] = current_j; |
| 573 delete this[j]; | 553 delete this[j]; |
| 574 } | 554 } |
| 575 } | 555 } |
| 576 } | 556 } |
| 577 return this; | 557 return this; |
| 578 } | 558 } |
| 579 | 559 |
| 580 | 560 |
| 581 function ObservedArrayShift(len) { | |
| 582 var first = this[0]; | |
| 583 | |
| 584 EnqueueSpliceRecord(this, 0, [first], 1, 0); | |
| 585 | |
| 586 try { | |
| 587 BeginPerformSplice(this); | |
| 588 SimpleMove(this, 0, 1, len, 0); | |
| 589 this.length = len - 1; | |
| 590 } finally { | |
| 591 EndPerformSplice(this); | |
| 592 } | |
| 593 | |
| 594 return first; | |
| 595 } | |
| 596 | |
| 597 function ArrayShift() { | 561 function ArrayShift() { |
| 598 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 562 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
| 599 throw MakeTypeError("called_on_null_or_undefined", | 563 throw MakeTypeError("called_on_null_or_undefined", |
| 600 ["Array.prototype.shift"]); | 564 ["Array.prototype.shift"]); |
| 601 } | 565 } |
| 602 | 566 |
| 603 var len = TO_UINT32(this.length); | 567 var len = TO_UINT32(this.length); |
| 604 | 568 |
| 605 if (len === 0) { | 569 if (len === 0) { |
| 606 this.length = 0; | 570 this.length = 0; |
| 607 return; | 571 return; |
| 608 } | 572 } |
| 609 | 573 |
| 610 if (%IsObserved(this)) | |
| 611 return ObservedArrayShift.call(this, len); | |
| 612 | |
| 613 var first = this[0]; | 574 var first = this[0]; |
| 614 | 575 |
| 615 if (IS_ARRAY(this)) { | 576 if (IS_ARRAY(this) && !%IsObserved(this)) { |
| 616 SmartMove(this, 0, 1, len, 0); | 577 SmartMove(this, 0, 1, len, 0); |
| 617 } else { | 578 } else { |
| 618 SimpleMove(this, 0, 1, len, 0); | 579 SimpleMove(this, 0, 1, len, 0); |
| 619 } | 580 } |
| 620 | 581 |
| 621 this.length = len - 1; | 582 this.length = len - 1; |
| 622 | 583 |
| 623 return first; | 584 return first; |
| 624 } | 585 } |
| 625 | 586 |
| 626 function ObservedArrayUnshift() { | |
| 627 var len = TO_UINT32(this.length); | |
| 628 var num_arguments = %_ArgumentsLength(); | |
| 629 | |
| 630 EnqueueSpliceRecord(this, 0, [], 0, num_arguments); | |
| 631 | |
| 632 try { | |
| 633 BeginPerformSplice(this); | |
| 634 SimpleMove(this, 0, 0, len, num_arguments); | |
| 635 for (var i = 0; i < num_arguments; i++) { | |
| 636 this[i] = %_Arguments(i); | |
| 637 } | |
| 638 this.length = len + num_arguments; | |
| 639 } finally { | |
| 640 EndPerformSplice(this); | |
| 641 } | |
| 642 | |
| 643 return len + num_arguments; | |
| 644 } | |
| 645 | 587 |
| 646 function ArrayUnshift(arg1) { // length == 1 | 588 function ArrayUnshift(arg1) { // length == 1 |
| 647 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 589 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
| 648 throw MakeTypeError("called_on_null_or_undefined", | 590 throw MakeTypeError("called_on_null_or_undefined", |
| 649 ["Array.prototype.unshift"]); | 591 ["Array.prototype.unshift"]); |
| 650 } | 592 } |
| 651 | 593 |
| 652 if (%IsObserved(this)) | |
| 653 return ObservedArrayUnshift.apply(this, arguments); | |
| 654 | |
| 655 var len = TO_UINT32(this.length); | 594 var len = TO_UINT32(this.length); |
| 656 var num_arguments = %_ArgumentsLength(); | 595 var num_arguments = %_ArgumentsLength(); |
| 657 | 596 |
| 658 if (IS_ARRAY(this)) { | 597 if (IS_ARRAY(this) && !%IsObserved(this)) { |
| 659 SmartMove(this, 0, 0, len, num_arguments); | 598 SmartMove(this, 0, 0, len, num_arguments); |
| 660 } else { | 599 } else { |
| 661 SimpleMove(this, 0, 0, len, num_arguments); | 600 SimpleMove(this, 0, 0, len, num_arguments); |
| 662 } | 601 } |
| 663 | 602 |
| 664 for (var i = 0; i < num_arguments; i++) { | 603 for (var i = 0; i < num_arguments; i++) { |
| 665 this[i] = %_Arguments(i); | 604 this[i] = %_Arguments(i); |
| 666 } | 605 } |
| 667 | 606 |
| 668 this.length = len + num_arguments; | 607 this.length = len + num_arguments; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 } else { | 648 } else { |
| 710 SimpleSlice(this, start_i, end_i - start_i, len, result); | 649 SimpleSlice(this, start_i, end_i - start_i, len, result); |
| 711 } | 650 } |
| 712 | 651 |
| 713 result.length = end_i - start_i; | 652 result.length = end_i - start_i; |
| 714 | 653 |
| 715 return result; | 654 return result; |
| 716 } | 655 } |
| 717 | 656 |
| 718 | 657 |
| 719 function ComputeSpliceStartIndex(start_i, len) { | |
| 720 if (start_i < 0) { | |
| 721 start_i += len; | |
| 722 return start_i < 0 ? 0 : start_i; | |
| 723 } | |
| 724 | |
| 725 return start_i > len ? len : start_i; | |
| 726 } | |
| 727 | |
| 728 | |
| 729 function ComputeSpliceDeleteCount(delete_count, num_arguments, len, start_i) { | |
| 730 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is | |
| 731 // given as a request to delete all the elements from the start. | |
| 732 // And it differs from the case of undefined delete count. | |
| 733 // This does not follow ECMA-262, but we do the same for | |
| 734 // compatibility. | |
| 735 var del_count = 0; | |
| 736 if (num_arguments == 1) | |
| 737 return len - start_i; | |
| 738 | |
| 739 del_count = TO_INTEGER(delete_count); | |
| 740 if (del_count < 0) | |
| 741 return 0; | |
| 742 | |
| 743 if (del_count > len - start_i) | |
| 744 return len - start_i; | |
| 745 | |
| 746 return del_count; | |
| 747 } | |
| 748 | |
| 749 | |
| 750 function ObservedArraySplice(start, delete_count) { | |
| 751 var num_arguments = %_ArgumentsLength(); | |
| 752 var len = TO_UINT32(this.length); | |
| 753 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len); | |
| 754 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len, | |
| 755 start_i); | |
| 756 var deleted_elements = []; | |
| 757 deleted_elements.length = del_count; | |
| 758 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; | |
| 759 | |
| 760 try { | |
| 761 BeginPerformSplice(this); | |
| 762 | |
| 763 SimpleSlice(this, start_i, del_count, len, deleted_elements); | |
| 764 SimpleMove(this, start_i, del_count, len, num_elements_to_add); | |
| 765 | |
| 766 // Insert the arguments into the resulting array in | |
| 767 // place of the deleted elements. | |
| 768 var i = start_i; | |
| 769 var arguments_index = 2; | |
| 770 var arguments_length = %_ArgumentsLength(); | |
| 771 while (arguments_index < arguments_length) { | |
| 772 this[i++] = %_Arguments(arguments_index++); | |
| 773 } | |
| 774 this.length = len - del_count + num_elements_to_add; | |
| 775 | |
| 776 } finally { | |
| 777 EndPerformSplice(this); | |
| 778 if (deleted_elements.length || num_elements_to_add) { | |
| 779 EnqueueSpliceRecord(this, | |
| 780 start_i, | |
| 781 deleted_elements.slice(), | |
| 782 deleted_elements.length, | |
| 783 num_elements_to_add); | |
| 784 } | |
| 785 } | |
| 786 | |
| 787 // Return the deleted elements. | |
| 788 return deleted_elements; | |
| 789 } | |
| 790 | |
| 791 | |
| 792 function ArraySplice(start, delete_count) { | 658 function ArraySplice(start, delete_count) { |
| 793 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 659 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
| 794 throw MakeTypeError("called_on_null_or_undefined", | 660 throw MakeTypeError("called_on_null_or_undefined", |
| 795 ["Array.prototype.splice"]); | 661 ["Array.prototype.splice"]); |
| 796 } | 662 } |
| 797 | 663 |
| 798 if (%IsObserved(this)) | 664 var num_arguments = %_ArgumentsLength(); |
| 799 return ObservedArraySplice.apply(this, arguments); | |
| 800 | 665 |
| 801 var num_arguments = %_ArgumentsLength(); | |
| 802 var len = TO_UINT32(this.length); | 666 var len = TO_UINT32(this.length); |
| 803 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len); | 667 var start_i = TO_INTEGER(start); |
| 804 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len, | 668 |
| 805 start_i); | 669 if (start_i < 0) { |
| 670 start_i += len; |
| 671 if (start_i < 0) start_i = 0; |
| 672 } else { |
| 673 if (start_i > len) start_i = len; |
| 674 } |
| 675 |
| 676 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is |
| 677 // given as a request to delete all the elements from the start. |
| 678 // And it differs from the case of undefined delete count. |
| 679 // This does not follow ECMA-262, but we do the same for |
| 680 // compatibility. |
| 681 var del_count = 0; |
| 682 if (num_arguments == 1) { |
| 683 del_count = len - start_i; |
| 684 } else { |
| 685 del_count = TO_INTEGER(delete_count); |
| 686 if (del_count < 0) del_count = 0; |
| 687 if (del_count > len - start_i) del_count = len - start_i; |
| 688 } |
| 689 |
| 806 var deleted_elements = []; | 690 var deleted_elements = []; |
| 807 deleted_elements.length = del_count; | 691 deleted_elements.length = del_count; |
| 808 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; | 692 |
| 693 // Number of elements to add. |
| 694 var num_additional_args = 0; |
| 695 if (num_arguments > 2) { |
| 696 num_additional_args = num_arguments - 2; |
| 697 } |
| 809 | 698 |
| 810 var use_simple_splice = true; | 699 var use_simple_splice = true; |
| 700 |
| 811 if (IS_ARRAY(this) && | 701 if (IS_ARRAY(this) && |
| 812 num_elements_to_add !== del_count) { | 702 !%IsObserved(this) && |
| 703 num_additional_args !== del_count) { |
| 813 // If we are only deleting/moving a few things near the end of the | 704 // If we are only deleting/moving a few things near the end of the |
| 814 // array then the simple version is going to be faster, because it | 705 // array then the simple version is going to be faster, because it |
| 815 // doesn't touch most of the array. | 706 // doesn't touch most of the array. |
| 816 var estimated_non_hole_elements = %EstimateNumberOfElements(this); | 707 var estimated_non_hole_elements = %EstimateNumberOfElements(this); |
| 817 if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) { | 708 if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) { |
| 818 use_simple_splice = false; | 709 use_simple_splice = false; |
| 819 } | 710 } |
| 820 } | 711 } |
| 821 | 712 |
| 822 if (use_simple_splice) { | 713 if (use_simple_splice) { |
| 823 SimpleSlice(this, start_i, del_count, len, deleted_elements); | 714 SimpleSlice(this, start_i, del_count, len, deleted_elements); |
| 824 SimpleMove(this, start_i, del_count, len, num_elements_to_add); | 715 SimpleMove(this, start_i, del_count, len, num_additional_args); |
| 825 } else { | 716 } else { |
| 826 SmartSlice(this, start_i, del_count, len, deleted_elements); | 717 SmartSlice(this, start_i, del_count, len, deleted_elements); |
| 827 SmartMove(this, start_i, del_count, len, num_elements_to_add); | 718 SmartMove(this, start_i, del_count, len, num_additional_args); |
| 828 } | 719 } |
| 829 | 720 |
| 830 // Insert the arguments into the resulting array in | 721 // Insert the arguments into the resulting array in |
| 831 // place of the deleted elements. | 722 // place of the deleted elements. |
| 832 var i = start_i; | 723 var i = start_i; |
| 833 var arguments_index = 2; | 724 var arguments_index = 2; |
| 834 var arguments_length = %_ArgumentsLength(); | 725 var arguments_length = %_ArgumentsLength(); |
| 835 while (arguments_index < arguments_length) { | 726 while (arguments_index < arguments_length) { |
| 836 this[i++] = %_Arguments(arguments_index++); | 727 this[i++] = %_Arguments(arguments_index++); |
| 837 } | 728 } |
| 838 this.length = len - del_count + num_elements_to_add; | 729 this.length = len - del_count + num_additional_args; |
| 839 | 730 |
| 840 // Return the deleted elements. | 731 // Return the deleted elements. |
| 841 return deleted_elements; | 732 return deleted_elements; |
| 842 } | 733 } |
| 843 | 734 |
| 844 | 735 |
| 845 function ArraySort(comparefn) { | 736 function ArraySort(comparefn) { |
| 846 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 737 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
| 847 throw MakeTypeError("called_on_null_or_undefined", | 738 throw MakeTypeError("called_on_null_or_undefined", |
| 848 ["Array.prototype.sort"]); | 739 ["Array.prototype.sort"]); |
| (...skipping 808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1657 )); | 1548 )); |
| 1658 | 1549 |
| 1659 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( | 1550 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( |
| 1660 "join", getFunction("join", ArrayJoin), | 1551 "join", getFunction("join", ArrayJoin), |
| 1661 "pop", getFunction("pop", ArrayPop), | 1552 "pop", getFunction("pop", ArrayPop), |
| 1662 "push", getFunction("push", ArrayPush) | 1553 "push", getFunction("push", ArrayPush) |
| 1663 )); | 1554 )); |
| 1664 } | 1555 } |
| 1665 | 1556 |
| 1666 SetUpArray(); | 1557 SetUpArray(); |
| OLD | NEW |