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

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

Issue 2655623004: [runtime] Fix Array.prototype.concat with complex @@species (Closed)
Patch Set: fixing argument type 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<HeapObject> storage,
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_(
564 ExceedsLimitField::encode(false) | 564 FastElementsField::encode(fast_elements) |
565 IsFixedArrayField::encode(storage->IsFixedArray())) { 565 ExceedsLimitField::encode(false) |
566 IsFixedArrayField::encode(storage->IsFixedArray()) |
567 HasSimpleElementsField::encode(storage->IsFixedArray() ||
568 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 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
1215 } 1225 }
1216 if (failure) break; 1226 if (failure) break;
1217 } 1227 }
1218 } 1228 }
1219 if (!failure) { 1229 if (!failure) {
1220 return *isolate->factory()->NewJSArrayWithElements(storage, kind, j); 1230 return *isolate->factory()->NewJSArrayWithElements(storage, kind, j);
1221 } 1231 }
1222 // In case of failure, fall through. 1232 // In case of failure, fall through.
1223 } 1233 }
1224 1234
1225 Handle<Object> storage; 1235 Handle<HeapObject> storage;
1226 if (fast_case) { 1236 if (fast_case) {
1227 // The backing storage array must have non-existing elements to preserve 1237 // The backing storage array must have non-existing elements to preserve
1228 // holes across concat operations. 1238 // holes across concat operations.
1229 storage = 1239 storage =
1230 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); 1240 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
1231 } else if (is_array_species) { 1241 } else if (is_array_species) {
1232 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 1242 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
1233 uint32_t at_least_space_for = 1243 uint32_t at_least_space_for =
1234 estimate_nof_elements + (estimate_nof_elements >> 2); 1244 estimate_nof_elements + (estimate_nof_elements >> 2);
1235 storage = SeededNumberDictionary::New(isolate, at_least_space_for); 1245 storage = SeededNumberDictionary::New(isolate, at_least_space_for);
1236 } else { 1246 } else {
1237 DCHECK(species->IsConstructor()); 1247 DCHECK(species->IsConstructor());
1238 Handle<Object> length(Smi::kZero, isolate); 1248 Handle<Object> length(Smi::kZero, isolate);
1239 Handle<Object> storage_object; 1249 Handle<Object> storage_object;
1240 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1250 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1241 isolate, storage_object, 1251 isolate, storage_object,
1242 Execution::New(isolate, species, species, 1, &length)); 1252 Execution::New(isolate, species, species, 1, &length));
1243 storage = storage_object; 1253 storage = Handle<HeapObject>::cast(storage_object);
1244 } 1254 }
1245 1255
1246 ArrayConcatVisitor visitor(isolate, storage, fast_case); 1256 ArrayConcatVisitor visitor(isolate, storage, fast_case);
1247 1257
1248 for (int i = 0; i < argument_count; i++) { 1258 for (int i = 0; i < argument_count; i++) {
1249 Handle<Object> obj((*args)[i], isolate); 1259 Handle<Object> obj((*args)[i], isolate);
1250 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj); 1260 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj);
1251 MAYBE_RETURN(spreadable, isolate->heap()->exception()); 1261 MAYBE_RETURN(spreadable, isolate->heap()->exception());
1252 if (spreadable.FromJust()) { 1262 if (spreadable.FromJust()) {
1253 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj); 1263 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj);
(...skipping 1491 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