Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1266)

Side by Side Diff: src/builtins.cc

Issue 1577043002: Support @@species in Array.prototype.concat (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix exceptions thrown from exceeding array length Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | test/mjsunit/harmony/array-species.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #include "src/builtins.h" 5 #include "src/builtins.h"
6 6
7 #include "src/api.h" 7 #include "src/api.h"
8 #include "src/api-natives.h" 8 #include "src/api-natives.h"
9 #include "src/arguments.h" 9 #include "src/arguments.h"
10 #include "src/base/once.h" 10 #include "src/base/once.h"
(...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 * or a dictionary for sparse array. Since Dictionary is a subtype 620 * or a dictionary for sparse array. Since Dictionary is a subtype
621 * of FixedArray, the class can be used by both fast and slow cases. 621 * of FixedArray, the class can be used by both fast and slow cases.
622 * The second parameter of the constructor, fast_elements, specifies 622 * The second parameter of the constructor, fast_elements, specifies
623 * whether the storage is a FixedArray or Dictionary. 623 * whether the storage is a FixedArray or Dictionary.
624 * 624 *
625 * An index limit is used to deal with the situation that a result array 625 * An index limit is used to deal with the situation that a result array
626 * length overflows 32-bit non-negative integer. 626 * length overflows 32-bit non-negative integer.
627 */ 627 */
628 class ArrayConcatVisitor { 628 class ArrayConcatVisitor {
629 public: 629 public:
630 ArrayConcatVisitor(Isolate* isolate, Handle<FixedArray> storage, 630 ArrayConcatVisitor(Isolate* isolate, Handle<Object> storage,
631 bool fast_elements) 631 bool fast_elements)
632 : isolate_(isolate), 632 : isolate_(isolate),
633 storage_(Handle<FixedArray>::cast( 633 storage_(isolate->global_handles()->Create(*storage)),
634 isolate->global_handles()->Create(*storage))),
635 index_offset_(0u), 634 index_offset_(0u),
636 bit_field_(FastElementsField::encode(fast_elements) | 635 bit_field_(FastElementsField::encode(fast_elements) |
637 ExceedsLimitField::encode(false)) {} 636 ExceedsLimitField::encode(false) |
637 IsFixedArrayField::encode(storage->IsFixedArray())) {
638 DCHECK(!(this->fast_elements() && !is_fixed_array()));
639 }
638 640
639 ~ArrayConcatVisitor() { clear_storage(); } 641 ~ArrayConcatVisitor() { clear_storage(); }
640 642
641 void visit(uint32_t i, Handle<Object> elm) { 643 bool visit(uint32_t i, Handle<Object> elm) {
644 uint32_t index = index_offset_ + i;
645
646 if (!is_fixed_array()) {
647 Handle<Object> element_value;
648 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
649 isolate_, element_value,
650 Object::SetElement(isolate_, storage_, index, elm, STRICT), false);
651 return true;
652 }
653
642 if (i >= JSObject::kMaxElementCount - index_offset_) { 654 if (i >= JSObject::kMaxElementCount - index_offset_) {
643 set_exceeds_array_limit(true); 655 set_exceeds_array_limit(true);
644 return; 656 // Exception hasn't been thrown at this point. Return true to
657 // break out, and caller will throw. !visit would imply that
658 // there is already a pending exception.
659 return true;
645 } 660 }
646 uint32_t index = index_offset_ + i;
647 661
648 if (fast_elements()) { 662 if (fast_elements()) {
649 if (index < static_cast<uint32_t>(storage_->length())) { 663 if (index < static_cast<uint32_t>(storage_fixed_array()->length())) {
650 storage_->set(index, *elm); 664 storage_fixed_array()->set(index, *elm);
651 return; 665 return true;
652 } 666 }
653 // Our initial estimate of length was foiled, possibly by 667 // Our initial estimate of length was foiled, possibly by
654 // getters on the arrays increasing the length of later arrays 668 // getters on the arrays increasing the length of later arrays
655 // during iteration. 669 // during iteration.
656 // This shouldn't happen in anything but pathological cases. 670 // This shouldn't happen in anything but pathological cases.
657 SetDictionaryMode(); 671 SetDictionaryMode();
658 // Fall-through to dictionary mode. 672 // Fall-through to dictionary mode.
659 } 673 }
660 DCHECK(!fast_elements()); 674 DCHECK(!fast_elements());
661 Handle<SeededNumberDictionary> dict( 675 Handle<SeededNumberDictionary> dict(
662 SeededNumberDictionary::cast(*storage_)); 676 SeededNumberDictionary::cast(*storage_));
663 // The object holding this backing store has just been allocated, so 677 // The object holding this backing store has just been allocated, so
664 // it cannot yet be used as a prototype. 678 // it cannot yet be used as a prototype.
665 Handle<SeededNumberDictionary> result = 679 Handle<SeededNumberDictionary> result =
666 SeededNumberDictionary::AtNumberPut(dict, index, elm, false); 680 SeededNumberDictionary::AtNumberPut(dict, index, elm, false);
667 if (!result.is_identical_to(dict)) { 681 if (!result.is_identical_to(dict)) {
668 // Dictionary needed to grow. 682 // Dictionary needed to grow.
669 clear_storage(); 683 clear_storage();
670 set_storage(*result); 684 set_storage(*result);
671 } 685 }
686 return true;
672 } 687 }
673 688
674 void increase_index_offset(uint32_t delta) { 689 void increase_index_offset(uint32_t delta) {
675 if (JSObject::kMaxElementCount - index_offset_ < delta) { 690 if (JSObject::kMaxElementCount - index_offset_ < delta) {
676 index_offset_ = JSObject::kMaxElementCount; 691 index_offset_ = JSObject::kMaxElementCount;
677 } else { 692 } else {
678 index_offset_ += delta; 693 index_offset_ += delta;
679 } 694 }
680 // If the initial length estimate was off (see special case in visit()), 695 // If the initial length estimate was off (see special case in visit()),
681 // but the array blowing the limit didn't contain elements beyond the 696 // but the array blowing the limit didn't contain elements beyond the
682 // provided-for index range, go to dictionary mode now. 697 // provided-for index range, go to dictionary mode now.
683 if (fast_elements() && 698 if (fast_elements() &&
684 index_offset_ > 699 index_offset_ >
685 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) { 700 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
686 SetDictionaryMode(); 701 SetDictionaryMode();
687 } 702 }
688 } 703 }
689 704
690 bool exceeds_array_limit() const { 705 bool exceeds_array_limit() const {
691 return ExceedsLimitField::decode(bit_field_); 706 return ExceedsLimitField::decode(bit_field_);
692 } 707 }
693 708
694 Handle<JSArray> ToArray() { 709 Handle<JSArray> ToArray() {
710 DCHECK(is_fixed_array());
695 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); 711 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
696 Handle<Object> length = 712 Handle<Object> length =
697 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); 713 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
698 Handle<Map> map = JSObject::GetElementsTransitionMap( 714 Handle<Map> map = JSObject::GetElementsTransitionMap(
699 array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); 715 array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
700 array->set_map(*map); 716 array->set_map(*map);
701 array->set_length(*length); 717 array->set_length(*length);
702 array->set_elements(*storage_); 718 array->set_elements(*storage_fixed_array());
703 return array; 719 return array;
704 } 720 }
705 721
722 // Storage is either a FixedArray (if is_fixed_array()) or a JSReciever
723 // (otherwise)
724 Handle<FixedArray> storage_fixed_array() {
725 DCHECK(is_fixed_array());
726 return Handle<FixedArray>::cast(storage_);
727 }
728 Handle<JSReceiver> storage_jsreceiver() {
729 DCHECK(!is_fixed_array());
730 return Handle<JSReceiver>::cast(storage_);
731 }
732
706 private: 733 private:
707 // Convert storage to dictionary mode. 734 // Convert storage to dictionary mode.
708 void SetDictionaryMode() { 735 void SetDictionaryMode() {
709 DCHECK(fast_elements()); 736 DCHECK(fast_elements() && is_fixed_array());
710 Handle<FixedArray> current_storage(*storage_); 737 Handle<FixedArray> current_storage = storage_fixed_array();
711 Handle<SeededNumberDictionary> slow_storage( 738 Handle<SeededNumberDictionary> slow_storage(
712 SeededNumberDictionary::New(isolate_, current_storage->length())); 739 SeededNumberDictionary::New(isolate_, current_storage->length()));
713 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); 740 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
714 for (uint32_t i = 0; i < current_length; i++) { 741 for (uint32_t i = 0; i < current_length; i++) {
715 HandleScope loop_scope(isolate_); 742 HandleScope loop_scope(isolate_);
716 Handle<Object> element(current_storage->get(i), isolate_); 743 Handle<Object> element(current_storage->get(i), isolate_);
717 if (!element->IsTheHole()) { 744 if (!element->IsTheHole()) {
718 // The object holding this backing store has just been allocated, so 745 // The object holding this backing store has just been allocated, so
719 // it cannot yet be used as a prototype. 746 // it cannot yet be used as a prototype.
720 Handle<SeededNumberDictionary> new_storage = 747 Handle<SeededNumberDictionary> new_storage =
721 SeededNumberDictionary::AtNumberPut(slow_storage, i, element, 748 SeededNumberDictionary::AtNumberPut(slow_storage, i, element,
722 false); 749 false);
723 if (!new_storage.is_identical_to(slow_storage)) { 750 if (!new_storage.is_identical_to(slow_storage)) {
724 slow_storage = loop_scope.CloseAndEscape(new_storage); 751 slow_storage = loop_scope.CloseAndEscape(new_storage);
725 } 752 }
726 } 753 }
727 } 754 }
728 clear_storage(); 755 clear_storage();
729 set_storage(*slow_storage); 756 set_storage(*slow_storage);
730 set_fast_elements(false); 757 set_fast_elements(false);
731 } 758 }
732 759
733 inline void clear_storage() { 760 inline void clear_storage() {
734 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location()); 761 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
735 } 762 }
736 763
737 inline void set_storage(FixedArray* storage) { 764 inline void set_storage(FixedArray* storage) {
738 storage_ = 765 DCHECK(is_fixed_array());
739 Handle<FixedArray>::cast(isolate_->global_handles()->Create(storage)); 766 storage_ = isolate_->global_handles()->Create(storage);
740 } 767 }
741 768
742 class FastElementsField : public BitField<bool, 0, 1> {}; 769 class FastElementsField : public BitField<bool, 0, 1> {};
743 class ExceedsLimitField : public BitField<bool, 1, 1> {}; 770 class ExceedsLimitField : public BitField<bool, 1, 1> {};
771 class IsFixedArrayField : public BitField<bool, 2, 1> {};
744 772
745 bool fast_elements() const { return FastElementsField::decode(bit_field_); } 773 bool fast_elements() const { return FastElementsField::decode(bit_field_); }
746 void set_fast_elements(bool fast) { 774 void set_fast_elements(bool fast) {
747 bit_field_ = FastElementsField::update(bit_field_, fast); 775 bit_field_ = FastElementsField::update(bit_field_, fast);
748 } 776 }
749 void set_exceeds_array_limit(bool exceeds) { 777 void set_exceeds_array_limit(bool exceeds) {
750 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds); 778 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
751 } 779 }
780 bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); }
752 781
753 Isolate* isolate_; 782 Isolate* isolate_;
754 Handle<FixedArray> storage_; // Always a global handle. 783 Handle<Object> storage_; // Always a global handle.
755 // Index after last seen index. Always less than or equal to 784 // Index after last seen index. Always less than or equal to
756 // JSObject::kMaxElementCount. 785 // JSObject::kMaxElementCount.
757 uint32_t index_offset_; 786 uint32_t index_offset_;
758 uint32_t bit_field_; 787 uint32_t bit_field_;
759 }; 788 };
760 789
761 790
762 uint32_t EstimateElementCount(Handle<JSArray> array) { 791 uint32_t EstimateElementCount(Handle<JSArray> array) {
763 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 792 uint32_t length = static_cast<uint32_t>(array->length()->Number());
764 int element_count = 0; 793 int element_count = 0;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 // External arrays are always dense. 844 // External arrays are always dense.
816 return length; 845 return length;
817 } 846 }
818 // As an estimate, we assume that the prototype doesn't contain any 847 // As an estimate, we assume that the prototype doesn't contain any
819 // inherited elements. 848 // inherited elements.
820 return element_count; 849 return element_count;
821 } 850 }
822 851
823 852
824 template <class ExternalArrayClass, class ElementType> 853 template <class ExternalArrayClass, class ElementType>
825 void IterateTypedArrayElements(Isolate* isolate, Handle<JSObject> receiver, 854 bool IterateTypedArrayElements(Isolate* isolate, Handle<JSObject> receiver,
826 bool elements_are_ints, 855 bool elements_are_ints,
827 bool elements_are_guaranteed_smis, 856 bool elements_are_guaranteed_smis,
828 ArrayConcatVisitor* visitor) { 857 ArrayConcatVisitor* visitor) {
829 Handle<ExternalArrayClass> array( 858 Handle<ExternalArrayClass> array(
830 ExternalArrayClass::cast(receiver->elements())); 859 ExternalArrayClass::cast(receiver->elements()));
831 uint32_t len = static_cast<uint32_t>(array->length()); 860 uint32_t len = static_cast<uint32_t>(array->length());
832 861
833 DCHECK(visitor != NULL); 862 DCHECK(visitor != NULL);
834 if (elements_are_ints) { 863 if (elements_are_ints) {
835 if (elements_are_guaranteed_smis) { 864 if (elements_are_guaranteed_smis) {
836 for (uint32_t j = 0; j < len; j++) { 865 for (uint32_t j = 0; j < len; j++) {
837 HandleScope loop_scope(isolate); 866 HandleScope loop_scope(isolate);
838 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))), 867 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
839 isolate); 868 isolate);
840 visitor->visit(j, e); 869 if (!visitor->visit(j, e)) return false;
841 } 870 }
842 } else { 871 } else {
843 for (uint32_t j = 0; j < len; j++) { 872 for (uint32_t j = 0; j < len; j++) {
844 HandleScope loop_scope(isolate); 873 HandleScope loop_scope(isolate);
845 int64_t val = static_cast<int64_t>(array->get_scalar(j)); 874 int64_t val = static_cast<int64_t>(array->get_scalar(j));
846 if (Smi::IsValid(static_cast<intptr_t>(val))) { 875 if (Smi::IsValid(static_cast<intptr_t>(val))) {
847 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate); 876 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
848 visitor->visit(j, e); 877 if (!visitor->visit(j, e)) return false;
849 } else { 878 } else {
850 Handle<Object> e = 879 Handle<Object> e =
851 isolate->factory()->NewNumber(static_cast<ElementType>(val)); 880 isolate->factory()->NewNumber(static_cast<ElementType>(val));
852 visitor->visit(j, e); 881 if (!visitor->visit(j, e)) return false;
853 } 882 }
854 } 883 }
855 } 884 }
856 } else { 885 } else {
857 for (uint32_t j = 0; j < len; j++) { 886 for (uint32_t j = 0; j < len; j++) {
858 HandleScope loop_scope(isolate); 887 HandleScope loop_scope(isolate);
859 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j)); 888 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
860 visitor->visit(j, e); 889 if (!visitor->visit(j, e)) return false;
861 } 890 }
862 } 891 }
892 return true;
863 } 893 }
864 894
865 895
866 // Used for sorting indices in a List<uint32_t>. 896 // Used for sorting indices in a List<uint32_t>.
867 int compareUInt32(const uint32_t* ap, const uint32_t* bp) { 897 int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
868 uint32_t a = *ap; 898 uint32_t a = *ap;
869 uint32_t b = *bp; 899 uint32_t b = *bp;
870 return (a == b) ? 0 : (a < b) ? -1 : 1; 900 return (a == b) ? 0 : (a < b) ? -1 : 1;
871 } 901 }
872 902
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 uint32_t length, ArrayConcatVisitor* visitor) { 999 uint32_t length, ArrayConcatVisitor* visitor) {
970 for (uint32_t i = 0; i < length; ++i) { 1000 for (uint32_t i = 0; i < length; ++i) {
971 HandleScope loop_scope(isolate); 1001 HandleScope loop_scope(isolate);
972 Maybe<bool> maybe = JSReceiver::HasElement(receiver, i); 1002 Maybe<bool> maybe = JSReceiver::HasElement(receiver, i);
973 if (!maybe.IsJust()) return false; 1003 if (!maybe.IsJust()) return false;
974 if (maybe.FromJust()) { 1004 if (maybe.FromJust()) {
975 Handle<Object> element_value; 1005 Handle<Object> element_value;
976 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_value, 1006 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_value,
977 Object::GetElement(isolate, receiver, i), 1007 Object::GetElement(isolate, receiver, i),
978 false); 1008 false);
979 visitor->visit(i, element_value); 1009 if (!visitor->visit(i, element_value)) return false;
980 } 1010 }
981 } 1011 }
982 visitor->increase_index_offset(length); 1012 visitor->increase_index_offset(length);
983 return true; 1013 return true;
984 } 1014 }
985 1015
986 1016
987 /** 1017 /**
988 * A helper function that visits "array" elements of a JSReceiver in numerical 1018 * A helper function that visits "array" elements of a JSReceiver in numerical
989 * order. 1019 * order.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1029 case FAST_HOLEY_ELEMENTS: { 1059 case FAST_HOLEY_ELEMENTS: {
1030 // Run through the elements FixedArray and use HasElement and GetElement 1060 // Run through the elements FixedArray and use HasElement and GetElement
1031 // to check the prototype for missing elements. 1061 // to check the prototype for missing elements.
1032 Handle<FixedArray> elements(FixedArray::cast(array->elements())); 1062 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
1033 int fast_length = static_cast<int>(length); 1063 int fast_length = static_cast<int>(length);
1034 DCHECK(fast_length <= elements->length()); 1064 DCHECK(fast_length <= elements->length());
1035 for (int j = 0; j < fast_length; j++) { 1065 for (int j = 0; j < fast_length; j++) {
1036 HandleScope loop_scope(isolate); 1066 HandleScope loop_scope(isolate);
1037 Handle<Object> element_value(elements->get(j), isolate); 1067 Handle<Object> element_value(elements->get(j), isolate);
1038 if (!element_value->IsTheHole()) { 1068 if (!element_value->IsTheHole()) {
1039 visitor->visit(j, element_value); 1069 if (!visitor->visit(j, element_value)) return false;
1040 } else { 1070 } else {
1041 Maybe<bool> maybe = JSReceiver::HasElement(array, j); 1071 Maybe<bool> maybe = JSReceiver::HasElement(array, j);
1042 if (!maybe.IsJust()) return false; 1072 if (!maybe.IsJust()) return false;
1043 if (maybe.FromJust()) { 1073 if (maybe.FromJust()) {
1044 // Call GetElement on array, not its prototype, or getters won't 1074 // Call GetElement on array, not its prototype, or getters won't
1045 // have the correct receiver. 1075 // have the correct receiver.
1046 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1076 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1047 isolate, element_value, Object::GetElement(isolate, array, j), 1077 isolate, element_value, Object::GetElement(isolate, array, j),
1048 false); 1078 false);
1049 visitor->visit(j, element_value); 1079 if (!visitor->visit(j, element_value)) return false;
1050 } 1080 }
1051 } 1081 }
1052 } 1082 }
1053 break; 1083 break;
1054 } 1084 }
1055 case FAST_HOLEY_DOUBLE_ELEMENTS: 1085 case FAST_HOLEY_DOUBLE_ELEMENTS:
1056 case FAST_DOUBLE_ELEMENTS: { 1086 case FAST_DOUBLE_ELEMENTS: {
1057 // Empty array is FixedArray but not FixedDoubleArray. 1087 // Empty array is FixedArray but not FixedDoubleArray.
1058 if (length == 0) break; 1088 if (length == 0) break;
1059 // Run through the elements FixedArray and use HasElement and GetElement 1089 // Run through the elements FixedArray and use HasElement and GetElement
1060 // to check the prototype for missing elements. 1090 // to check the prototype for missing elements.
1061 if (array->elements()->IsFixedArray()) { 1091 if (array->elements()->IsFixedArray()) {
1062 DCHECK(array->elements()->length() == 0); 1092 DCHECK(array->elements()->length() == 0);
1063 break; 1093 break;
1064 } 1094 }
1065 Handle<FixedDoubleArray> elements( 1095 Handle<FixedDoubleArray> elements(
1066 FixedDoubleArray::cast(array->elements())); 1096 FixedDoubleArray::cast(array->elements()));
1067 int fast_length = static_cast<int>(length); 1097 int fast_length = static_cast<int>(length);
1068 DCHECK(fast_length <= elements->length()); 1098 DCHECK(fast_length <= elements->length());
1069 for (int j = 0; j < fast_length; j++) { 1099 for (int j = 0; j < fast_length; j++) {
1070 HandleScope loop_scope(isolate); 1100 HandleScope loop_scope(isolate);
1071 if (!elements->is_the_hole(j)) { 1101 if (!elements->is_the_hole(j)) {
1072 double double_value = elements->get_scalar(j); 1102 double double_value = elements->get_scalar(j);
1073 Handle<Object> element_value = 1103 Handle<Object> element_value =
1074 isolate->factory()->NewNumber(double_value); 1104 isolate->factory()->NewNumber(double_value);
1075 visitor->visit(j, element_value); 1105 if (!visitor->visit(j, element_value)) return false;
1076 } else { 1106 } else {
1077 Maybe<bool> maybe = JSReceiver::HasElement(array, j); 1107 Maybe<bool> maybe = JSReceiver::HasElement(array, j);
1078 if (!maybe.IsJust()) return false; 1108 if (!maybe.IsJust()) return false;
1079 if (maybe.FromJust()) { 1109 if (maybe.FromJust()) {
1080 // Call GetElement on array, not its prototype, or getters won't 1110 // Call GetElement on array, not its prototype, or getters won't
1081 // have the correct receiver. 1111 // have the correct receiver.
1082 Handle<Object> element_value; 1112 Handle<Object> element_value;
1083 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1113 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1084 isolate, element_value, Object::GetElement(isolate, array, j), 1114 isolate, element_value, Object::GetElement(isolate, array, j),
1085 false); 1115 false);
1086 visitor->visit(j, element_value); 1116 if (!visitor->visit(j, element_value)) return false;
1087 } 1117 }
1088 } 1118 }
1089 } 1119 }
1090 break; 1120 break;
1091 } 1121 }
1092 case DICTIONARY_ELEMENTS: { 1122 case DICTIONARY_ELEMENTS: {
1093 // CollectElementIndices() can't be called when there's a JSProxy 1123 // CollectElementIndices() can't be called when there's a JSProxy
1094 // on the prototype chain. 1124 // on the prototype chain.
1095 for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd(); 1125 for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd();
1096 iter.Advance()) { 1126 iter.Advance()) {
1097 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { 1127 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
1098 return IterateElementsSlow(isolate, array, length, visitor); 1128 return IterateElementsSlow(isolate, array, length, visitor);
1099 } 1129 }
1100 } 1130 }
1101 Handle<SeededNumberDictionary> dict(array->element_dictionary()); 1131 Handle<SeededNumberDictionary> dict(array->element_dictionary());
1102 List<uint32_t> indices(dict->Capacity() / 2); 1132 List<uint32_t> indices(dict->Capacity() / 2);
1103 // Collect all indices in the object and the prototypes less 1133 // Collect all indices in the object and the prototypes less
1104 // than length. This might introduce duplicates in the indices list. 1134 // than length. This might introduce duplicates in the indices list.
1105 CollectElementIndices(array, length, &indices); 1135 CollectElementIndices(array, length, &indices);
1106 indices.Sort(&compareUInt32); 1136 indices.Sort(&compareUInt32);
1107 int j = 0; 1137 int j = 0;
1108 int n = indices.length(); 1138 int n = indices.length();
1109 while (j < n) { 1139 while (j < n) {
1110 HandleScope loop_scope(isolate); 1140 HandleScope loop_scope(isolate);
1111 uint32_t index = indices[j]; 1141 uint32_t index = indices[j];
1112 Handle<Object> element; 1142 Handle<Object> element;
1113 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1143 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1114 isolate, element, Object::GetElement(isolate, array, index), false); 1144 isolate, element, Object::GetElement(isolate, array, index), false);
1115 visitor->visit(index, element); 1145 if (!visitor->visit(index, element)) return false;
1116 // Skip to next different index (i.e., omit duplicates). 1146 // Skip to next different index (i.e., omit duplicates).
1117 do { 1147 do {
1118 j++; 1148 j++;
1119 } while (j < n && indices[j] == index); 1149 } while (j < n && indices[j] == index);
1120 } 1150 }
1121 break; 1151 break;
1122 } 1152 }
1123 case UINT8_CLAMPED_ELEMENTS: { 1153 case UINT8_CLAMPED_ELEMENTS: {
1124 Handle<FixedUint8ClampedArray> pixels( 1154 Handle<FixedUint8ClampedArray> pixels(
1125 FixedUint8ClampedArray::cast(array->elements())); 1155 FixedUint8ClampedArray::cast(array->elements()));
1126 for (uint32_t j = 0; j < length; j++) { 1156 for (uint32_t j = 0; j < length; j++) {
1127 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); 1157 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
1128 visitor->visit(j, e); 1158 visitor->visit(j, e);
1129 } 1159 }
1130 break; 1160 break;
1131 } 1161 }
1132 case INT8_ELEMENTS: { 1162 case INT8_ELEMENTS: {
1133 IterateTypedArrayElements<FixedInt8Array, int8_t>(isolate, array, true, 1163 if (!IterateTypedArrayElements<FixedInt8Array, int8_t>(
1134 true, visitor); 1164 isolate, array, true, true, visitor))
1165 return false;
1135 break; 1166 break;
1136 } 1167 }
1137 case UINT8_ELEMENTS: { 1168 case UINT8_ELEMENTS: {
1138 IterateTypedArrayElements<FixedUint8Array, uint8_t>(isolate, array, true, 1169 if (!IterateTypedArrayElements<FixedUint8Array, uint8_t>(
1139 true, visitor); 1170 isolate, array, true, true, visitor))
1171 return false;
1140 break; 1172 break;
1141 } 1173 }
1142 case INT16_ELEMENTS: { 1174 case INT16_ELEMENTS: {
1143 IterateTypedArrayElements<FixedInt16Array, int16_t>(isolate, array, true, 1175 if (!IterateTypedArrayElements<FixedInt16Array, int16_t>(
1144 true, visitor); 1176 isolate, array, true, true, visitor))
1177 return false;
1145 break; 1178 break;
1146 } 1179 }
1147 case UINT16_ELEMENTS: { 1180 case UINT16_ELEMENTS: {
1148 IterateTypedArrayElements<FixedUint16Array, uint16_t>( 1181 if (!IterateTypedArrayElements<FixedUint16Array, uint16_t>(
1149 isolate, array, true, true, visitor); 1182 isolate, array, true, true, visitor))
1183 return false;
1150 break; 1184 break;
1151 } 1185 }
1152 case INT32_ELEMENTS: { 1186 case INT32_ELEMENTS: {
1153 IterateTypedArrayElements<FixedInt32Array, int32_t>(isolate, array, true, 1187 if (!IterateTypedArrayElements<FixedInt32Array, int32_t>(
1154 false, visitor); 1188 isolate, array, true, false, visitor))
1189 return false;
1155 break; 1190 break;
1156 } 1191 }
1157 case UINT32_ELEMENTS: { 1192 case UINT32_ELEMENTS: {
1158 IterateTypedArrayElements<FixedUint32Array, uint32_t>( 1193 if (!IterateTypedArrayElements<FixedUint32Array, uint32_t>(
1159 isolate, array, true, false, visitor); 1194 isolate, array, true, false, visitor))
1195 return false;
1160 break; 1196 break;
1161 } 1197 }
1162 case FLOAT32_ELEMENTS: { 1198 case FLOAT32_ELEMENTS: {
1163 IterateTypedArrayElements<FixedFloat32Array, float>(isolate, array, false, 1199 if (!IterateTypedArrayElements<FixedFloat32Array, float>(
1164 false, visitor); 1200 isolate, array, false, false, visitor))
1201 return false;
1165 break; 1202 break;
1166 } 1203 }
1167 case FLOAT64_ELEMENTS: { 1204 case FLOAT64_ELEMENTS: {
1168 IterateTypedArrayElements<FixedFloat64Array, double>( 1205 if (!IterateTypedArrayElements<FixedFloat64Array, double>(
1169 isolate, array, false, false, visitor); 1206 isolate, array, false, false, visitor))
1207 return false;
1170 break; 1208 break;
1171 } 1209 }
1172 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 1210 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1173 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { 1211 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
1174 for (uint32_t index = 0; index < length; index++) { 1212 for (uint32_t index = 0; index < length; index++) {
1175 HandleScope loop_scope(isolate); 1213 HandleScope loop_scope(isolate);
1176 Handle<Object> element; 1214 Handle<Object> element;
1177 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1215 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1178 isolate, element, Object::GetElement(isolate, array, index), false); 1216 isolate, element, Object::GetElement(isolate, array, index), false);
1179 visitor->visit(index, element); 1217 if (!visitor->visit(index, element)) return false;
1180 } 1218 }
1181 break; 1219 break;
1182 } 1220 }
1183 } 1221 }
1184 visitor->increase_index_offset(length); 1222 visitor->increase_index_offset(length);
1185 return true; 1223 return true;
1186 } 1224 }
1187 1225
1188 1226
1189 bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { 1227 bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) {
(...skipping 13 matching lines...) Expand all
1203 Handle<Object> value; 1241 Handle<Object> value;
1204 MaybeHandle<Object> maybeValue = 1242 MaybeHandle<Object> maybeValue =
1205 i::Runtime::GetObjectProperty(isolate, obj, key); 1243 i::Runtime::GetObjectProperty(isolate, obj, key);
1206 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); 1244 if (!maybeValue.ToHandle(&value)) return Nothing<bool>();
1207 if (!value->IsUndefined()) return Just(value->BooleanValue()); 1245 if (!value->IsUndefined()) return Just(value->BooleanValue());
1208 } 1246 }
1209 return Object::IsArray(obj); 1247 return Object::IsArray(obj);
1210 } 1248 }
1211 1249
1212 1250
1213 Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) { 1251 Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
1252 Isolate* isolate) {
1214 int argument_count = args->length(); 1253 int argument_count = args->length();
1215 1254
1255 bool is_array_species = *species == isolate->context()->array_function();
1256
1216 // Pass 1: estimate the length and number of elements of the result. 1257 // Pass 1: estimate the length and number of elements of the result.
1217 // The actual length can be larger if any of the arguments have getters 1258 // The actual length can be larger if any of the arguments have getters
1218 // that mutate other arguments (but will otherwise be precise). 1259 // that mutate other arguments (but will otherwise be precise).
1219 // The number of elements is precise if there are no inherited elements. 1260 // The number of elements is precise if there are no inherited elements.
1220 1261
1221 ElementsKind kind = FAST_SMI_ELEMENTS; 1262 ElementsKind kind = FAST_SMI_ELEMENTS;
1222 1263
1223 uint32_t estimate_result_length = 0; 1264 uint32_t estimate_result_length = 0;
1224 uint32_t estimate_nof_elements = 0; 1265 uint32_t estimate_nof_elements = 0;
1225 for (int i = 0; i < argument_count; i++) { 1266 for (int i = 0; i < argument_count; i++) {
(...skipping 30 matching lines...) Expand all
1256 if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) { 1297 if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) {
1257 estimate_nof_elements = JSObject::kMaxElementCount; 1298 estimate_nof_elements = JSObject::kMaxElementCount;
1258 } else { 1299 } else {
1259 estimate_nof_elements += element_estimate; 1300 estimate_nof_elements += element_estimate;
1260 } 1301 }
1261 } 1302 }
1262 1303
1263 // If estimated number of elements is more than half of length, a 1304 // If estimated number of elements is more than half of length, a
1264 // fixed array (fast case) is more time and space-efficient than a 1305 // fixed array (fast case) is more time and space-efficient than a
1265 // dictionary. 1306 // dictionary.
1266 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; 1307 bool fast_case =
1308 is_array_species && (estimate_nof_elements * 2) >= estimate_result_length;
1267 1309
1268 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) { 1310 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) {
1269 Handle<FixedArrayBase> storage = 1311 Handle<FixedArrayBase> storage =
1270 isolate->factory()->NewFixedDoubleArray(estimate_result_length); 1312 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
1271 int j = 0; 1313 int j = 0;
1272 bool failure = false; 1314 bool failure = false;
1273 if (estimate_result_length > 0) { 1315 if (estimate_result_length > 0) {
1274 Handle<FixedDoubleArray> double_storage = 1316 Handle<FixedDoubleArray> double_storage =
1275 Handle<FixedDoubleArray>::cast(storage); 1317 Handle<FixedDoubleArray>::cast(storage);
1276 for (int i = 0; i < argument_count; i++) { 1318 for (int i = 0; i < argument_count; i++) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1340 Handle<Map> map; 1382 Handle<Map> map;
1341 map = JSObject::GetElementsTransitionMap(array, kind); 1383 map = JSObject::GetElementsTransitionMap(array, kind);
1342 array->set_map(*map); 1384 array->set_map(*map);
1343 array->set_length(length); 1385 array->set_length(length);
1344 array->set_elements(*storage); 1386 array->set_elements(*storage);
1345 return *array; 1387 return *array;
1346 } 1388 }
1347 // In case of failure, fall through. 1389 // In case of failure, fall through.
1348 } 1390 }
1349 1391
1350 Handle<FixedArray> storage; 1392 Handle<Object> storage;
1351 if (fast_case) { 1393 if (fast_case) {
1352 // The backing storage array must have non-existing elements to preserve 1394 // The backing storage array must have non-existing elements to preserve
1353 // holes across concat operations. 1395 // holes across concat operations.
1354 storage = 1396 storage =
1355 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); 1397 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
1356 } else { 1398 } else if (is_array_species) {
1357 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 1399 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
1358 uint32_t at_least_space_for = 1400 uint32_t at_least_space_for =
1359 estimate_nof_elements + (estimate_nof_elements >> 2); 1401 estimate_nof_elements + (estimate_nof_elements >> 2);
1360 storage = Handle<FixedArray>::cast( 1402 storage = SeededNumberDictionary::New(isolate, at_least_space_for);
1361 SeededNumberDictionary::New(isolate, at_least_space_for)); 1403 } else {
1404 DCHECK(species->IsConstructor());
1405 Handle<Object> length(Smi::FromInt(0), isolate);
1406 Handle<Object> storage_object;
1407 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1408 isolate, storage_object,
1409 Execution::New(isolate, species, species, 1, &length));
1410 storage = storage_object;
1362 } 1411 }
1363 1412
1364 ArrayConcatVisitor visitor(isolate, storage, fast_case); 1413 ArrayConcatVisitor visitor(isolate, storage, fast_case);
1365 1414
1366 for (int i = 0; i < argument_count; i++) { 1415 for (int i = 0; i < argument_count; i++) {
1367 Handle<Object> obj((*args)[i], isolate); 1416 Handle<Object> obj((*args)[i], isolate);
1368 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj); 1417 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj);
1369 MAYBE_RETURN(spreadable, isolate->heap()->exception()); 1418 MAYBE_RETURN(spreadable, isolate->heap()->exception());
1370 if (spreadable.FromJust()) { 1419 if (spreadable.FromJust()) {
1371 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj); 1420 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj);
1372 if (!IterateElements(isolate, object, &visitor)) { 1421 if (!IterateElements(isolate, object, &visitor)) {
1373 return isolate->heap()->exception(); 1422 return isolate->heap()->exception();
1374 } 1423 }
1375 } else { 1424 } else {
1376 visitor.visit(0, obj); 1425 visitor.visit(0, obj);
1377 visitor.increase_index_offset(1); 1426 visitor.increase_index_offset(1);
1378 } 1427 }
1379 } 1428 }
1380 1429
1381 if (visitor.exceeds_array_limit()) { 1430 if (visitor.exceeds_array_limit()) {
1382 THROW_NEW_ERROR_RETURN_FAILURE( 1431 THROW_NEW_ERROR_RETURN_FAILURE(
1383 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); 1432 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength));
1384 } 1433 }
1385 return *visitor.ToArray(); 1434
1435 if (is_array_species) {
1436 return *visitor.ToArray();
1437 } else {
1438 return *visitor.storage_jsreceiver();
1439 }
1386 } 1440 }
1387 1441
1388 1442
1389 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { 1443 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) {
1390 if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) { 1444 if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) {
1391 return MaybeHandle<JSArray>(); 1445 return MaybeHandle<JSArray>();
1392 } 1446 }
1393 int n_arguments = args->length(); 1447 int n_arguments = args->length();
1394 int result_len = 0; 1448 int result_len = 0;
1395 { 1449 {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1439 THROW_NEW_ERROR_RETURN_FAILURE( 1493 THROW_NEW_ERROR_RETURN_FAILURE(
1440 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, 1494 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
1441 isolate->factory()->NewStringFromAsciiChecked( 1495 isolate->factory()->NewStringFromAsciiChecked(
1442 "Array.prototype.concat"))); 1496 "Array.prototype.concat")));
1443 } 1497 }
1444 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1498 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1445 isolate, receiver, Object::ToObject(isolate, args.receiver())); 1499 isolate, receiver, Object::ToObject(isolate, args.receiver()));
1446 args[0] = *receiver; 1500 args[0] = *receiver;
1447 1501
1448 Handle<JSArray> result_array; 1502 Handle<JSArray> result_array;
1449 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { 1503
1450 return *result_array; 1504 // Reading @@species happens before anything else with a side effect, so
1505 // we can do it here to determine whether to take the fast path.
1506 Handle<Object> species;
1507 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1508 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver));
1509 if (*species == isolate->context()->native_context()->array_function()) {
1510 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
1511 return *result_array;
1512 }
1513 if (isolate->has_pending_exception()) return isolate->heap()->exception();
1451 } 1514 }
1452 if (isolate->has_pending_exception()) return isolate->heap()->exception(); 1515 return Slow_ArrayConcat(&args, species, isolate);
1453 return Slow_ArrayConcat(&args, isolate);
1454 } 1516 }
1455 1517
1456 1518
1457 // ES6 22.1.2.2 Array.isArray 1519 // ES6 22.1.2.2 Array.isArray
1458 BUILTIN(ArrayIsArray) { 1520 BUILTIN(ArrayIsArray) {
1459 HandleScope scope(isolate); 1521 HandleScope scope(isolate);
1460 DCHECK_EQ(2, args.length()); 1522 DCHECK_EQ(2, args.length());
1461 Handle<Object> object = args.at<Object>(1); 1523 Handle<Object> object = args.at<Object>(1);
1462 Maybe<bool> result = Object::IsArray(object); 1524 Maybe<bool> result = Object::IsArray(object);
1463 MAYBE_RETURN(result, isolate->heap()->exception()); 1525 MAYBE_RETURN(result, isolate->heap()->exception());
(...skipping 2590 matching lines...) Expand 10 before | Expand all | Expand 10 after
4054 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) 4116 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
4055 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) 4117 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
4056 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) 4118 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H)
4057 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) 4119 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
4058 #undef DEFINE_BUILTIN_ACCESSOR_C 4120 #undef DEFINE_BUILTIN_ACCESSOR_C
4059 #undef DEFINE_BUILTIN_ACCESSOR_A 4121 #undef DEFINE_BUILTIN_ACCESSOR_A
4060 4122
4061 4123
4062 } // namespace internal 4124 } // namespace internal
4063 } // namespace v8 4125 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/harmony/array-species.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698