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 |