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

Side by Side Diff: src/builtins/builtins-array.cc

Issue 2655623004: [runtime] Fix Array.prototype.concat with complex @@species (Closed)
Patch Set: do instance_type check Created 3 years, 10 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/regress/regress-crbug-682194.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 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 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/builtins.h" 5 #include "src/builtins/builtins.h"
6 #include "src/builtins/builtins-utils.h" 6 #include "src/builtins/builtins-utils.h"
7 7
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/code-stub-assembler.h" 9 #include "src/code-stub-assembler.h"
10 #include "src/contexts.h" 10 #include "src/contexts.h"
(...skipping 537 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 * or a dictionary for sparse array. Since Dictionary is a subtype 548 * or a dictionary for sparse array. Since Dictionary is a subtype
549 * of FixedArray, the class can be used by both fast and slow cases. 549 * of FixedArray, the class can be used by both fast and slow cases.
550 * The second parameter of the constructor, fast_elements, specifies 550 * The second parameter of the constructor, fast_elements, specifies
551 * whether the storage is a FixedArray or Dictionary. 551 * whether the storage is a FixedArray or Dictionary.
552 * 552 *
553 * An index limit is used to deal with the situation that a result array 553 * An index limit is used to deal with the situation that a result array
554 * length overflows 32-bit non-negative integer. 554 * length overflows 32-bit non-negative integer.
555 */ 555 */
556 class ArrayConcatVisitor { 556 class ArrayConcatVisitor {
557 public: 557 public:
558 ArrayConcatVisitor(Isolate* isolate, Handle<Object> storage, 558 ArrayConcatVisitor(Isolate* isolate, Handle<Object> storage,
Toon Verwaest 2017/01/25 01:44:30 Handle<HeapObject>
559 bool fast_elements) 559 bool fast_elements)
560 : isolate_(isolate), 560 : isolate_(isolate),
561 storage_(isolate->global_handles()->Create(*storage)), 561 storage_(isolate->global_handles()->Create(*storage)),
562 index_offset_(0u), 562 index_offset_(0u),
563 bit_field_(FastElementsField::encode(fast_elements) | 563 bit_field_(FastElementsField::encode(fast_elements) |
564 ExceedsLimitField::encode(false) | 564 ExceedsLimitField::encode(false) |
565 IsFixedArrayField::encode(storage->IsFixedArray())) { 565 IsFixedArrayField::encode(storage->IsFixedArray()) |
566 HasSimpleElementsField::encode(
567 storage->IsFixedArray() ||
568 HeapObject::cast(*storage)->map()->instance_type() >
569 LAST_CUSTOM_ELEMENTS_RECEIVER)) {
566 DCHECK(!(this->fast_elements() && !is_fixed_array())); 570 DCHECK(!(this->fast_elements() && !is_fixed_array()));
567 } 571 }
568 572
569 ~ArrayConcatVisitor() { clear_storage(); } 573 ~ArrayConcatVisitor() { clear_storage(); }
570 574
571 MUST_USE_RESULT bool visit(uint32_t i, Handle<Object> elm) { 575 MUST_USE_RESULT bool visit(uint32_t i, Handle<Object> elm) {
572 uint32_t index = index_offset_ + i; 576 uint32_t index = index_offset_ + i;
573 577
574 if (i >= JSObject::kMaxElementCount - index_offset_) { 578 if (i >= JSObject::kMaxElementCount - index_offset_) {
575 set_exceeds_array_limit(true); 579 set_exceeds_array_limit(true);
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 array->set_map(*map); 649 array->set_map(*map);
646 array->set_length(*length); 650 array->set_length(*length);
647 array->set_elements(*storage_fixed_array()); 651 array->set_elements(*storage_fixed_array());
648 return array; 652 return array;
649 } 653 }
650 654
651 // Storage is either a FixedArray (if is_fixed_array()) or a JSReciever 655 // Storage is either a FixedArray (if is_fixed_array()) or a JSReciever
652 // (otherwise) 656 // (otherwise)
653 Handle<FixedArray> storage_fixed_array() { 657 Handle<FixedArray> storage_fixed_array() {
654 DCHECK(is_fixed_array()); 658 DCHECK(is_fixed_array());
659 DCHECK(has_simple_elements());
655 return Handle<FixedArray>::cast(storage_); 660 return Handle<FixedArray>::cast(storage_);
656 } 661 }
657 Handle<JSReceiver> storage_jsreceiver() { 662 Handle<JSReceiver> storage_jsreceiver() {
658 DCHECK(!is_fixed_array()); 663 DCHECK(!is_fixed_array());
659 return Handle<JSReceiver>::cast(storage_); 664 return Handle<JSReceiver>::cast(storage_);
660 } 665 }
666 bool has_simple_elements() const {
667 return HasSimpleElementsField::decode(bit_field_);
668 }
661 669
662 private: 670 private:
663 // Convert storage to dictionary mode. 671 // Convert storage to dictionary mode.
664 void SetDictionaryMode() { 672 void SetDictionaryMode() {
665 DCHECK(fast_elements() && is_fixed_array()); 673 DCHECK(fast_elements() && is_fixed_array());
666 Handle<FixedArray> current_storage = storage_fixed_array(); 674 Handle<FixedArray> current_storage = storage_fixed_array();
667 Handle<SeededNumberDictionary> slow_storage( 675 Handle<SeededNumberDictionary> slow_storage(
668 SeededNumberDictionary::New(isolate_, current_storage->length())); 676 SeededNumberDictionary::New(isolate_, current_storage->length()));
669 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); 677 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
670 FOR_WITH_HANDLE_SCOPE( 678 FOR_WITH_HANDLE_SCOPE(
(...skipping 13 matching lines...) Expand all
684 }); 692 });
685 clear_storage(); 693 clear_storage();
686 set_storage(*slow_storage); 694 set_storage(*slow_storage);
687 set_fast_elements(false); 695 set_fast_elements(false);
688 } 696 }
689 697
690 inline void clear_storage() { GlobalHandles::Destroy(storage_.location()); } 698 inline void clear_storage() { GlobalHandles::Destroy(storage_.location()); }
691 699
692 inline void set_storage(FixedArray* storage) { 700 inline void set_storage(FixedArray* storage) {
693 DCHECK(is_fixed_array()); 701 DCHECK(is_fixed_array());
702 DCHECK(has_simple_elements());
694 storage_ = isolate_->global_handles()->Create(storage); 703 storage_ = isolate_->global_handles()->Create(storage);
695 } 704 }
696 705
697 class FastElementsField : public BitField<bool, 0, 1> {}; 706 class FastElementsField : public BitField<bool, 0, 1> {};
698 class ExceedsLimitField : public BitField<bool, 1, 1> {}; 707 class ExceedsLimitField : public BitField<bool, 1, 1> {};
699 class IsFixedArrayField : public BitField<bool, 2, 1> {}; 708 class IsFixedArrayField : public BitField<bool, 2, 1> {};
709 class HasSimpleElementsField : public BitField<bool, 3, 1> {};
700 710
701 bool fast_elements() const { return FastElementsField::decode(bit_field_); } 711 bool fast_elements() const { return FastElementsField::decode(bit_field_); }
702 void set_fast_elements(bool fast) { 712 void set_fast_elements(bool fast) {
703 bit_field_ = FastElementsField::update(bit_field_, fast); 713 bit_field_ = FastElementsField::update(bit_field_, fast);
704 } 714 }
705 void set_exceeds_array_limit(bool exceeds) { 715 void set_exceeds_array_limit(bool exceeds) {
706 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds); 716 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
707 } 717 }
708 bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); } 718 bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); }
709 719
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
915 Handle<Object> element_value; 925 Handle<Object> element_value;
916 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 926 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
917 isolate, element_value, JSReceiver::GetElement(isolate, receiver, i), 927 isolate, element_value, JSReceiver::GetElement(isolate, receiver, i),
918 false); 928 false);
919 if (!visitor->visit(i, element_value)) return false; 929 if (!visitor->visit(i, element_value)) return false;
920 } 930 }
921 }); 931 });
922 visitor->increase_index_offset(length); 932 visitor->increase_index_offset(length);
923 return true; 933 return true;
924 } 934 }
925
926 /** 935 /**
927 * A helper function that visits "array" elements of a JSReceiver in numerical 936 * A helper function that visits "array" elements of a JSReceiver in numerical
928 * order. 937 * order.
929 * 938 *
930 * The visitor argument called for each existing element in the array 939 * The visitor argument called for each existing element in the array
931 * with the element index and the element's value. 940 * with the element index and the element's value.
932 * Afterwards it increments the base-index of the visitor by the array 941 * Afterwards it increments the base-index of the visitor by the array
933 * length. 942 * length.
934 * Returns false if any access threw an exception, otherwise true. 943 * Returns false if any access threw an exception, otherwise true.
935 */ 944 */
936 bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, 945 bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
937 ArrayConcatVisitor* visitor) { 946 ArrayConcatVisitor* visitor) {
938 uint32_t length = 0; 947 uint32_t length = 0;
939 948
940 if (receiver->IsJSArray()) { 949 if (receiver->IsJSArray()) {
941 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 950 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
942 length = static_cast<uint32_t>(array->length()->Number()); 951 length = static_cast<uint32_t>(array->length()->Number());
943 } else { 952 } else {
944 Handle<Object> val; 953 Handle<Object> val;
945 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 954 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
946 isolate, val, Object::GetLengthFromArrayLike(isolate, receiver), false); 955 isolate, val, Object::GetLengthFromArrayLike(isolate, receiver), false);
947 // TODO(caitp): Support larger element indexes (up to 2^53-1). 956 // TODO(caitp): Support larger element indexes (up to 2^53-1).
948 if (!val->ToUint32(&length)) { 957 if (!val->ToUint32(&length)) {
949 length = 0; 958 length = 0;
950 } 959 }
951 // TODO(cbruni): handle other element kind as well 960 // TODO(cbruni): handle other element kind as well
952 return IterateElementsSlow(isolate, receiver, length, visitor); 961 return IterateElementsSlow(isolate, receiver, length, visitor);
953 } 962 }
954 963
955 if (!HasOnlySimpleElements(isolate, *receiver)) { 964 if (!HasOnlySimpleElements(isolate, *receiver) ||
965 !visitor->has_simple_elements()) {
956 return IterateElementsSlow(isolate, receiver, length, visitor); 966 return IterateElementsSlow(isolate, receiver, length, visitor);
957 } 967 }
958 Handle<JSObject> array = Handle<JSObject>::cast(receiver); 968 Handle<JSObject> array = Handle<JSObject>::cast(receiver);
959 969
960 switch (array->GetElementsKind()) { 970 switch (array->GetElementsKind()) {
961 case FAST_SMI_ELEMENTS: 971 case FAST_SMI_ELEMENTS:
962 case FAST_ELEMENTS: 972 case FAST_ELEMENTS:
963 case FAST_HOLEY_SMI_ELEMENTS: 973 case FAST_HOLEY_SMI_ELEMENTS:
964 case FAST_HOLEY_ELEMENTS: { 974 case FAST_HOLEY_ELEMENTS: {
965 // Run through the elements FixedArray and use HasElement and GetElement 975 // Run through the elements FixedArray and use HasElement and GetElement
(...skipping 1779 matching lines...) Expand 10 before | Expand all | Expand 10 after
2745 Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation); 2755 Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation);
2746 Node* result = 2756 Node* result =
2747 assembler.CallRuntime(Runtime::kThrowTypeError, context, message, 2757 assembler.CallRuntime(Runtime::kThrowTypeError, context, message,
2748 assembler.HeapConstant(operation)); 2758 assembler.HeapConstant(operation));
2749 assembler.Return(result); 2759 assembler.Return(result);
2750 } 2760 }
2751 } 2761 }
2752 2762
2753 } // namespace internal 2763 } // namespace internal
2754 } // namespace v8 2764 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/regress/regress-crbug-682194.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698