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