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

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

Issue 2666543004: Merged: [runtime] Fix Array.prototype.concat with complex @@species (Closed)
Patch Set: 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/contexts.h" 9 #include "src/contexts.h"
10 #include "src/elements.h" 10 #include "src/elements.h"
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 * or a dictionary for sparse array. Since Dictionary is a subtype 401 * or a dictionary for sparse array. Since Dictionary is a subtype
402 * of FixedArray, the class can be used by both fast and slow cases. 402 * of FixedArray, the class can be used by both fast and slow cases.
403 * The second parameter of the constructor, fast_elements, specifies 403 * The second parameter of the constructor, fast_elements, specifies
404 * whether the storage is a FixedArray or Dictionary. 404 * whether the storage is a FixedArray or Dictionary.
405 * 405 *
406 * An index limit is used to deal with the situation that a result array 406 * An index limit is used to deal with the situation that a result array
407 * length overflows 32-bit non-negative integer. 407 * length overflows 32-bit non-negative integer.
408 */ 408 */
409 class ArrayConcatVisitor { 409 class ArrayConcatVisitor {
410 public: 410 public:
411 ArrayConcatVisitor(Isolate* isolate, Handle<Object> storage, 411 ArrayConcatVisitor(Isolate* isolate, Handle<HeapObject> storage,
412 bool fast_elements) 412 bool fast_elements)
413 : isolate_(isolate), 413 : isolate_(isolate),
414 storage_(isolate->global_handles()->Create(*storage)), 414 storage_(isolate->global_handles()->Create(*storage)),
415 index_offset_(0u), 415 index_offset_(0u),
416 bit_field_(FastElementsField::encode(fast_elements) | 416 bit_field_(
417 ExceedsLimitField::encode(false) | 417 FastElementsField::encode(fast_elements) |
418 IsFixedArrayField::encode(storage->IsFixedArray())) { 418 ExceedsLimitField::encode(false) |
419 IsFixedArrayField::encode(storage->IsFixedArray()) |
420 HasSimpleElementsField::encode(storage->IsFixedArray() ||
421 storage->map()->instance_type() >
422 LAST_CUSTOM_ELEMENTS_RECEIVER)) {
419 DCHECK(!(this->fast_elements() && !is_fixed_array())); 423 DCHECK(!(this->fast_elements() && !is_fixed_array()));
420 } 424 }
421 425
422 ~ArrayConcatVisitor() { clear_storage(); } 426 ~ArrayConcatVisitor() { clear_storage(); }
423 427
424 MUST_USE_RESULT bool visit(uint32_t i, Handle<Object> elm) { 428 MUST_USE_RESULT bool visit(uint32_t i, Handle<Object> elm) {
425 uint32_t index = index_offset_ + i; 429 uint32_t index = index_offset_ + i;
426 430
427 if (i >= JSObject::kMaxElementCount - index_offset_) { 431 if (i >= JSObject::kMaxElementCount - index_offset_) {
428 set_exceeds_array_limit(true); 432 set_exceeds_array_limit(true);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 array->set_map(*map); 501 array->set_map(*map);
498 array->set_length(*length); 502 array->set_length(*length);
499 array->set_elements(*storage_fixed_array()); 503 array->set_elements(*storage_fixed_array());
500 return array; 504 return array;
501 } 505 }
502 506
503 // Storage is either a FixedArray (if is_fixed_array()) or a JSReciever 507 // Storage is either a FixedArray (if is_fixed_array()) or a JSReciever
504 // (otherwise) 508 // (otherwise)
505 Handle<FixedArray> storage_fixed_array() { 509 Handle<FixedArray> storage_fixed_array() {
506 DCHECK(is_fixed_array()); 510 DCHECK(is_fixed_array());
511 DCHECK(has_simple_elements());
507 return Handle<FixedArray>::cast(storage_); 512 return Handle<FixedArray>::cast(storage_);
508 } 513 }
509 Handle<JSReceiver> storage_jsreceiver() { 514 Handle<JSReceiver> storage_jsreceiver() {
510 DCHECK(!is_fixed_array()); 515 DCHECK(!is_fixed_array());
511 return Handle<JSReceiver>::cast(storage_); 516 return Handle<JSReceiver>::cast(storage_);
512 } 517 }
518 bool has_simple_elements() const {
519 return HasSimpleElementsField::decode(bit_field_);
520 }
513 521
514 private: 522 private:
515 // Convert storage to dictionary mode. 523 // Convert storage to dictionary mode.
516 void SetDictionaryMode() { 524 void SetDictionaryMode() {
517 DCHECK(fast_elements() && is_fixed_array()); 525 DCHECK(fast_elements() && is_fixed_array());
518 Handle<FixedArray> current_storage = storage_fixed_array(); 526 Handle<FixedArray> current_storage = storage_fixed_array();
519 Handle<SeededNumberDictionary> slow_storage( 527 Handle<SeededNumberDictionary> slow_storage(
520 SeededNumberDictionary::New(isolate_, current_storage->length())); 528 SeededNumberDictionary::New(isolate_, current_storage->length()));
521 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); 529 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
522 FOR_WITH_HANDLE_SCOPE( 530 FOR_WITH_HANDLE_SCOPE(
(...skipping 12 matching lines...) Expand all
535 }); 543 });
536 clear_storage(); 544 clear_storage();
537 set_storage(*slow_storage); 545 set_storage(*slow_storage);
538 set_fast_elements(false); 546 set_fast_elements(false);
539 } 547 }
540 548
541 inline void clear_storage() { GlobalHandles::Destroy(storage_.location()); } 549 inline void clear_storage() { GlobalHandles::Destroy(storage_.location()); }
542 550
543 inline void set_storage(FixedArray* storage) { 551 inline void set_storage(FixedArray* storage) {
544 DCHECK(is_fixed_array()); 552 DCHECK(is_fixed_array());
553 DCHECK(has_simple_elements());
545 storage_ = isolate_->global_handles()->Create(storage); 554 storage_ = isolate_->global_handles()->Create(storage);
546 } 555 }
547 556
548 class FastElementsField : public BitField<bool, 0, 1> {}; 557 class FastElementsField : public BitField<bool, 0, 1> {};
549 class ExceedsLimitField : public BitField<bool, 1, 1> {}; 558 class ExceedsLimitField : public BitField<bool, 1, 1> {};
550 class IsFixedArrayField : public BitField<bool, 2, 1> {}; 559 class IsFixedArrayField : public BitField<bool, 2, 1> {};
560 class HasSimpleElementsField : public BitField<bool, 3, 1> {};
551 561
552 bool fast_elements() const { return FastElementsField::decode(bit_field_); } 562 bool fast_elements() const { return FastElementsField::decode(bit_field_); }
553 void set_fast_elements(bool fast) { 563 void set_fast_elements(bool fast) {
554 bit_field_ = FastElementsField::update(bit_field_, fast); 564 bit_field_ = FastElementsField::update(bit_field_, fast);
555 } 565 }
556 void set_exceeds_array_limit(bool exceeds) { 566 void set_exceeds_array_limit(bool exceeds) {
557 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds); 567 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
558 } 568 }
559 bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); } 569 bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); }
560 570
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
766 Handle<Object> element_value; 776 Handle<Object> element_value;
767 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 777 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
768 isolate, element_value, JSReceiver::GetElement(isolate, receiver, i), 778 isolate, element_value, JSReceiver::GetElement(isolate, receiver, i),
769 false); 779 false);
770 if (!visitor->visit(i, element_value)) return false; 780 if (!visitor->visit(i, element_value)) return false;
771 } 781 }
772 }); 782 });
773 visitor->increase_index_offset(length); 783 visitor->increase_index_offset(length);
774 return true; 784 return true;
775 } 785 }
776
777 /** 786 /**
778 * A helper function that visits "array" elements of a JSReceiver in numerical 787 * A helper function that visits "array" elements of a JSReceiver in numerical
779 * order. 788 * order.
780 * 789 *
781 * The visitor argument called for each existing element in the array 790 * The visitor argument called for each existing element in the array
782 * with the element index and the element's value. 791 * with the element index and the element's value.
783 * Afterwards it increments the base-index of the visitor by the array 792 * Afterwards it increments the base-index of the visitor by the array
784 * length. 793 * length.
785 * Returns false if any access threw an exception, otherwise true. 794 * Returns false if any access threw an exception, otherwise true.
786 */ 795 */
787 bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, 796 bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
788 ArrayConcatVisitor* visitor) { 797 ArrayConcatVisitor* visitor) {
789 uint32_t length = 0; 798 uint32_t length = 0;
790 799
791 if (receiver->IsJSArray()) { 800 if (receiver->IsJSArray()) {
792 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 801 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
793 length = static_cast<uint32_t>(array->length()->Number()); 802 length = static_cast<uint32_t>(array->length()->Number());
794 } else { 803 } else {
795 Handle<Object> val; 804 Handle<Object> val;
796 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 805 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
797 isolate, val, Object::GetLengthFromArrayLike(isolate, receiver), false); 806 isolate, val, Object::GetLengthFromArrayLike(isolate, receiver), false);
798 // TODO(caitp): Support larger element indexes (up to 2^53-1). 807 // TODO(caitp): Support larger element indexes (up to 2^53-1).
799 if (!val->ToUint32(&length)) { 808 if (!val->ToUint32(&length)) {
800 length = 0; 809 length = 0;
801 } 810 }
802 // TODO(cbruni): handle other element kind as well 811 // TODO(cbruni): handle other element kind as well
803 return IterateElementsSlow(isolate, receiver, length, visitor); 812 return IterateElementsSlow(isolate, receiver, length, visitor);
804 } 813 }
805 814
806 if (!HasOnlySimpleElements(isolate, *receiver)) { 815 if (!HasOnlySimpleElements(isolate, *receiver) ||
816 !visitor->has_simple_elements()) {
807 return IterateElementsSlow(isolate, receiver, length, visitor); 817 return IterateElementsSlow(isolate, receiver, length, visitor);
808 } 818 }
809 Handle<JSObject> array = Handle<JSObject>::cast(receiver); 819 Handle<JSObject> array = Handle<JSObject>::cast(receiver);
810 820
811 switch (array->GetElementsKind()) { 821 switch (array->GetElementsKind()) {
812 case FAST_SMI_ELEMENTS: 822 case FAST_SMI_ELEMENTS:
813 case FAST_ELEMENTS: 823 case FAST_ELEMENTS:
814 case FAST_HOLEY_SMI_ELEMENTS: 824 case FAST_HOLEY_SMI_ELEMENTS:
815 case FAST_HOLEY_ELEMENTS: { 825 case FAST_HOLEY_ELEMENTS: {
816 // Run through the elements FixedArray and use HasElement and GetElement 826 // Run through the elements FixedArray and use HasElement and GetElement
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
1065 } 1075 }
1066 if (failure) break; 1076 if (failure) break;
1067 } 1077 }
1068 } 1078 }
1069 if (!failure) { 1079 if (!failure) {
1070 return *isolate->factory()->NewJSArrayWithElements(storage, kind, j); 1080 return *isolate->factory()->NewJSArrayWithElements(storage, kind, j);
1071 } 1081 }
1072 // In case of failure, fall through. 1082 // In case of failure, fall through.
1073 } 1083 }
1074 1084
1075 Handle<Object> storage; 1085 Handle<HeapObject> storage;
1076 if (fast_case) { 1086 if (fast_case) {
1077 // The backing storage array must have non-existing elements to preserve 1087 // The backing storage array must have non-existing elements to preserve
1078 // holes across concat operations. 1088 // holes across concat operations.
1079 storage = 1089 storage =
1080 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); 1090 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
1081 } else if (is_array_species) { 1091 } else if (is_array_species) {
1082 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 1092 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
1083 uint32_t at_least_space_for = 1093 uint32_t at_least_space_for =
1084 estimate_nof_elements + (estimate_nof_elements >> 2); 1094 estimate_nof_elements + (estimate_nof_elements >> 2);
1085 storage = SeededNumberDictionary::New(isolate, at_least_space_for); 1095 storage = SeededNumberDictionary::New(isolate, at_least_space_for);
1086 } else { 1096 } else {
1087 DCHECK(species->IsConstructor()); 1097 DCHECK(species->IsConstructor());
1088 Handle<Object> length(Smi::kZero, isolate); 1098 Handle<Object> length(Smi::kZero, isolate);
1089 Handle<Object> storage_object; 1099 Handle<Object> storage_object;
1090 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1100 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1091 isolate, storage_object, 1101 isolate, storage_object,
1092 Execution::New(isolate, species, species, 1, &length)); 1102 Execution::New(isolate, species, species, 1, &length));
1093 storage = storage_object; 1103 storage = Handle<HeapObject>::cast(storage_object);
1094 } 1104 }
1095 1105
1096 ArrayConcatVisitor visitor(isolate, storage, fast_case); 1106 ArrayConcatVisitor visitor(isolate, storage, fast_case);
1097 1107
1098 for (int i = 0; i < argument_count; i++) { 1108 for (int i = 0; i < argument_count; i++) {
1099 Handle<Object> obj((*args)[i], isolate); 1109 Handle<Object> obj((*args)[i], isolate);
1100 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj); 1110 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj);
1101 MAYBE_RETURN(spreadable, isolate->heap()->exception()); 1111 MAYBE_RETURN(spreadable, isolate->heap()->exception());
1102 if (spreadable.FromJust()) { 1112 if (spreadable.FromJust()) {
1103 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj); 1113 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj);
(...skipping 1511 matching lines...) Expand 10 before | Expand all | Expand 10 after
2615 Runtime::kThrowIncompatibleMethodReceiver, context, 2625 Runtime::kThrowIncompatibleMethodReceiver, context,
2616 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( 2626 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked(
2617 "Array Iterator.prototype.next", TENURED)), 2627 "Array Iterator.prototype.next", TENURED)),
2618 iterator); 2628 iterator);
2619 assembler->Return(result); 2629 assembler->Return(result);
2620 } 2630 }
2621 } 2631 }
2622 2632
2623 } // namespace internal 2633 } // namespace internal
2624 } // namespace v8 2634 } // 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