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 |
398 // Removes the last element from the array and returns it. See | 415 // Removes the last element from the array and returns it. See |
399 // ECMA-262, section 15.4.4.6. | 416 // ECMA-262, section 15.4.4.6. |
400 function ArrayPop() { | 417 function ArrayPop() { |
401 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 418 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
402 throw MakeTypeError("called_on_null_or_undefined", | 419 throw MakeTypeError("called_on_null_or_undefined", |
403 ["Array.prototype.pop"]); | 420 ["Array.prototype.pop"]); |
404 } | 421 } |
405 | 422 |
406 var n = TO_UINT32(this.length); | 423 var n = TO_UINT32(this.length); |
407 if (n == 0) { | 424 if (n == 0) { |
408 this.length = n; | 425 this.length = n; |
409 return; | 426 return; |
410 } | 427 } |
| 428 |
| 429 if (%IsObserved(this)) |
| 430 return ObservedArrayPop.call(this, n); |
| 431 |
411 n--; | 432 n--; |
412 var value = this[n]; | 433 var value = this[n]; |
413 delete this[n]; | 434 delete this[n]; |
414 this.length = n; | 435 this.length = n; |
415 return value; | 436 return value; |
416 } | 437 } |
417 | 438 |
418 | 439 |
419 function ObservedArrayPush() { | 440 function ObservedArrayPush() { |
420 var n = TO_UINT32(this.length); | 441 var n = TO_UINT32(this.length); |
421 var m = %_ArgumentsLength(); | 442 var m = %_ArgumentsLength(); |
422 | 443 |
423 EnqueueSpliceRecord(this, n, [], 0, m); | 444 EnqueueSpliceRecord(this, n, [], 0, m); |
424 | 445 |
425 try { | 446 try { |
426 BeginPerformSplice(this); | 447 BeginPerformSplice(this); |
427 | |
428 for (var i = 0; i < m; i++) { | 448 for (var i = 0; i < m; i++) { |
429 this[i+n] = %_Arguments(i); | 449 this[i+n] = %_Arguments(i); |
430 } | 450 } |
431 this.length = n + m; | 451 this.length = n + m; |
432 } finally { | 452 } finally { |
433 EndPerformSplice(this); | 453 EndPerformSplice(this); |
434 } | 454 } |
435 | 455 |
436 return this.length; | 456 return this.length; |
437 } | 457 } |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 if (!IS_UNDEFINED(current_j) || j in this) { | 571 if (!IS_UNDEFINED(current_j) || j in this) { |
552 this[i] = current_j; | 572 this[i] = current_j; |
553 delete this[j]; | 573 delete this[j]; |
554 } | 574 } |
555 } | 575 } |
556 } | 576 } |
557 return this; | 577 return this; |
558 } | 578 } |
559 | 579 |
560 | 580 |
| 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 |
561 function ArrayShift() { | 597 function ArrayShift() { |
562 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 598 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
563 throw MakeTypeError("called_on_null_or_undefined", | 599 throw MakeTypeError("called_on_null_or_undefined", |
564 ["Array.prototype.shift"]); | 600 ["Array.prototype.shift"]); |
565 } | 601 } |
566 | 602 |
567 var len = TO_UINT32(this.length); | 603 var len = TO_UINT32(this.length); |
568 | 604 |
569 if (len === 0) { | 605 if (len === 0) { |
570 this.length = 0; | 606 this.length = 0; |
571 return; | 607 return; |
572 } | 608 } |
573 | 609 |
| 610 if (%IsObserved(this)) |
| 611 return ObservedArrayShift.call(this, len); |
| 612 |
574 var first = this[0]; | 613 var first = this[0]; |
575 | 614 |
576 if (IS_ARRAY(this) && !%IsObserved(this)) { | 615 if (IS_ARRAY(this)) { |
577 SmartMove(this, 0, 1, len, 0); | 616 SmartMove(this, 0, 1, len, 0); |
578 } else { | 617 } else { |
579 SimpleMove(this, 0, 1, len, 0); | 618 SimpleMove(this, 0, 1, len, 0); |
580 } | 619 } |
581 | 620 |
582 this.length = len - 1; | 621 this.length = len - 1; |
583 | 622 |
584 return first; | 623 return first; |
585 } | 624 } |
586 | 625 |
| 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 } |
587 | 645 |
588 function ArrayUnshift(arg1) { // length == 1 | 646 function ArrayUnshift(arg1) { // length == 1 |
589 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 647 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
590 throw MakeTypeError("called_on_null_or_undefined", | 648 throw MakeTypeError("called_on_null_or_undefined", |
591 ["Array.prototype.unshift"]); | 649 ["Array.prototype.unshift"]); |
592 } | 650 } |
593 | 651 |
| 652 if (%IsObserved(this)) |
| 653 return ObservedArrayUnshift.apply(this, arguments); |
| 654 |
594 var len = TO_UINT32(this.length); | 655 var len = TO_UINT32(this.length); |
595 var num_arguments = %_ArgumentsLength(); | 656 var num_arguments = %_ArgumentsLength(); |
596 | 657 |
597 if (IS_ARRAY(this) && !%IsObserved(this)) { | 658 if (IS_ARRAY(this)) { |
598 SmartMove(this, 0, 0, len, num_arguments); | 659 SmartMove(this, 0, 0, len, num_arguments); |
599 } else { | 660 } else { |
600 SimpleMove(this, 0, 0, len, num_arguments); | 661 SimpleMove(this, 0, 0, len, num_arguments); |
601 } | 662 } |
602 | 663 |
603 for (var i = 0; i < num_arguments; i++) { | 664 for (var i = 0; i < num_arguments; i++) { |
604 this[i] = %_Arguments(i); | 665 this[i] = %_Arguments(i); |
605 } | 666 } |
606 | 667 |
607 this.length = len + num_arguments; | 668 this.length = len + num_arguments; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
648 } else { | 709 } else { |
649 SimpleSlice(this, start_i, end_i - start_i, len, result); | 710 SimpleSlice(this, start_i, end_i - start_i, len, result); |
650 } | 711 } |
651 | 712 |
652 result.length = end_i - start_i; | 713 result.length = end_i - start_i; |
653 | 714 |
654 return result; | 715 return result; |
655 } | 716 } |
656 | 717 |
657 | 718 |
| 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 |
658 function ArraySplice(start, delete_count) { | 792 function ArraySplice(start, delete_count) { |
659 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 793 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
660 throw MakeTypeError("called_on_null_or_undefined", | 794 throw MakeTypeError("called_on_null_or_undefined", |
661 ["Array.prototype.splice"]); | 795 ["Array.prototype.splice"]); |
662 } | 796 } |
663 | 797 |
| 798 if (%IsObserved(this)) |
| 799 return ObservedArraySplice.apply(this, arguments); |
| 800 |
664 var num_arguments = %_ArgumentsLength(); | 801 var num_arguments = %_ArgumentsLength(); |
665 | |
666 var len = TO_UINT32(this.length); | 802 var len = TO_UINT32(this.length); |
667 var start_i = TO_INTEGER(start); | 803 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len); |
668 | 804 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len, |
669 if (start_i < 0) { | 805 start_i); |
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 | |
690 var deleted_elements = []; | 806 var deleted_elements = []; |
691 deleted_elements.length = del_count; | 807 deleted_elements.length = del_count; |
692 | 808 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; |
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 } | |
698 | 809 |
699 var use_simple_splice = true; | 810 var use_simple_splice = true; |
700 | |
701 if (IS_ARRAY(this) && | 811 if (IS_ARRAY(this) && |
702 !%IsObserved(this) && | 812 num_elements_to_add !== del_count) { |
703 num_additional_args !== del_count) { | |
704 // If we are only deleting/moving a few things near the end of the | 813 // If we are only deleting/moving a few things near the end of the |
705 // array then the simple version is going to be faster, because it | 814 // array then the simple version is going to be faster, because it |
706 // doesn't touch most of the array. | 815 // doesn't touch most of the array. |
707 var estimated_non_hole_elements = %EstimateNumberOfElements(this); | 816 var estimated_non_hole_elements = %EstimateNumberOfElements(this); |
708 if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) { | 817 if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) { |
709 use_simple_splice = false; | 818 use_simple_splice = false; |
710 } | 819 } |
711 } | 820 } |
712 | 821 |
713 if (use_simple_splice) { | 822 if (use_simple_splice) { |
714 SimpleSlice(this, start_i, del_count, len, deleted_elements); | 823 SimpleSlice(this, start_i, del_count, len, deleted_elements); |
715 SimpleMove(this, start_i, del_count, len, num_additional_args); | 824 SimpleMove(this, start_i, del_count, len, num_elements_to_add); |
716 } else { | 825 } else { |
717 SmartSlice(this, start_i, del_count, len, deleted_elements); | 826 SmartSlice(this, start_i, del_count, len, deleted_elements); |
718 SmartMove(this, start_i, del_count, len, num_additional_args); | 827 SmartMove(this, start_i, del_count, len, num_elements_to_add); |
719 } | 828 } |
720 | 829 |
721 // Insert the arguments into the resulting array in | 830 // Insert the arguments into the resulting array in |
722 // place of the deleted elements. | 831 // place of the deleted elements. |
723 var i = start_i; | 832 var i = start_i; |
724 var arguments_index = 2; | 833 var arguments_index = 2; |
725 var arguments_length = %_ArgumentsLength(); | 834 var arguments_length = %_ArgumentsLength(); |
726 while (arguments_index < arguments_length) { | 835 while (arguments_index < arguments_length) { |
727 this[i++] = %_Arguments(arguments_index++); | 836 this[i++] = %_Arguments(arguments_index++); |
728 } | 837 } |
729 this.length = len - del_count + num_additional_args; | 838 this.length = len - del_count + num_elements_to_add; |
730 | 839 |
731 // Return the deleted elements. | 840 // Return the deleted elements. |
732 return deleted_elements; | 841 return deleted_elements; |
733 } | 842 } |
734 | 843 |
735 | 844 |
736 function ArraySort(comparefn) { | 845 function ArraySort(comparefn) { |
737 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { | 846 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { |
738 throw MakeTypeError("called_on_null_or_undefined", | 847 throw MakeTypeError("called_on_null_or_undefined", |
739 ["Array.prototype.sort"]); | 848 ["Array.prototype.sort"]); |
(...skipping 808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1548 )); | 1657 )); |
1549 | 1658 |
1550 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( | 1659 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( |
1551 "join", getFunction("join", ArrayJoin), | 1660 "join", getFunction("join", ArrayJoin), |
1552 "pop", getFunction("pop", ArrayPop), | 1661 "pop", getFunction("pop", ArrayPop), |
1553 "push", getFunction("push", ArrayPush) | 1662 "push", getFunction("push", ArrayPush) |
1554 )); | 1663 )); |
1555 } | 1664 } |
1556 | 1665 |
1557 SetUpArray(); | 1666 SetUpArray(); |
OLD | NEW |