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) { | |
adamk
2013/05/20 17:51:50
Sad to see splice duplicated, as it's a bit more c
| |
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 806 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1546 )); | 1655 )); |
1547 | 1656 |
1548 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( | 1657 SetUpLockedPrototype(InternalPackedArray, $Array(), $Array( |
1549 "join", getFunction("join", ArrayJoin), | 1658 "join", getFunction("join", ArrayJoin), |
1550 "pop", getFunction("pop", ArrayPop), | 1659 "pop", getFunction("pop", ArrayPop), |
1551 "push", getFunction("push", ArrayPush) | 1660 "push", getFunction("push", ArrayPush) |
1552 )); | 1661 )); |
1553 } | 1662 } |
1554 | 1663 |
1555 SetUpArray(); | 1664 SetUpArray(); |
OLD | NEW |