Chromium Code Reviews| 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<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 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 1779 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 |