OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |