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

Side by Side Diff: src/builtins.cc

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

Powered by Google App Engine
This is Rietveld 408576698