 Chromium Code Reviews
 Chromium Code Reviews Issue 1560763002:
  Add Array support for @@species and subclassing  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 1560763002:
  Add Array support for @@species and subclassing  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| OLD | NEW | 
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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.h" | 5 #include "src/builtins.h" | 
| 6 | 6 | 
| 7 #include "src/api.h" | 7 #include "src/api.h" | 
| 8 #include "src/api-natives.h" | 8 #include "src/api-natives.h" | 
| 9 #include "src/arguments.h" | 9 #include "src/arguments.h" | 
| 10 #include "src/base/once.h" | 10 #include "src/base/once.h" | 
| (...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 451 BUILTIN(ArraySlice) { | 451 BUILTIN(ArraySlice) { | 
| 452 HandleScope scope(isolate); | 452 HandleScope scope(isolate); | 
| 453 Handle<Object> receiver = args.receiver(); | 453 Handle<Object> receiver = args.receiver(); | 
| 454 Handle<JSObject> object; | 454 Handle<JSObject> object; | 
| 455 Handle<FixedArrayBase> elms_obj; | 455 Handle<FixedArrayBase> elms_obj; | 
| 456 int len = -1; | 456 int len = -1; | 
| 457 int relative_start = 0; | 457 int relative_start = 0; | 
| 458 int relative_end = 0; | 458 int relative_end = 0; | 
| 459 bool is_sloppy_arguments = false; | 459 bool is_sloppy_arguments = false; | 
| 460 | 460 | 
| 461 // TODO(littledan): Look up @@species only once, not once here and | |
| 
adamk
2016/01/06 00:10:12
Please add a test that exercises this; that'll mak
 
Dan Ehrenberg
2016/01/07 00:42:57
Done
 | |
| 462 // again in the JS builtin. Pass the species out? | |
| 463 Handle<Object> species; | |
| 464 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 465 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); | |
| 466 if (*species != isolate->context()->native_context()->array_function()) { | |
| 467 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 468 } | |
| 461 if (receiver->IsJSArray()) { | 469 if (receiver->IsJSArray()) { | 
| 462 DisallowHeapAllocation no_gc; | 470 DisallowHeapAllocation no_gc; | 
| 463 JSArray* array = JSArray::cast(*receiver); | 471 JSArray* array = JSArray::cast(*receiver); | 
| 464 if (!array->HasFastElements() || | 472 if (!array->HasFastElements() || | 
| 465 !IsJSArrayFastElementMovingAllowed(isolate, array)) { | 473 !IsJSArrayFastElementMovingAllowed(isolate, array)) { | 
| 466 AllowHeapAllocation allow_allocation; | 474 AllowHeapAllocation allow_allocation; | 
| 467 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | 475 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | 
| 468 } | 476 } | 
| 469 len = Smi::cast(array->length())->value(); | 477 len = Smi::cast(array->length())->value(); | 
| 470 object = Handle<JSObject>::cast(receiver); | 478 object = Handle<JSObject>::cast(receiver); | 
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 536 | 544 | 
| 537 BUILTIN(ArraySplice) { | 545 BUILTIN(ArraySplice) { | 
| 538 HandleScope scope(isolate); | 546 HandleScope scope(isolate); | 
| 539 Handle<Object> receiver = args.receiver(); | 547 Handle<Object> receiver = args.receiver(); | 
| 540 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 548 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 
| 541 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); | 549 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); | 
| 542 Handle<FixedArrayBase> elms_obj; | 550 Handle<FixedArrayBase> elms_obj; | 
| 543 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 551 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 
| 544 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | 552 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | 
| 545 } | 553 } | 
| 554 // TODO(littledan): Look up @@species only once, not once here and | |
| 
adamk
2016/01/06 00:10:11
Same note as the TODO above.
 
Dan Ehrenberg
2016/01/07 00:42:57
Done
 | |
| 555 // again in the JS builtin. Pass the species out? | |
| 556 Handle<Object> species; | |
| 557 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 558 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); | |
| 559 if (*species != isolate->context()->native_context()->array_function()) { | |
| 560 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | |
| 561 } | |
| 546 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 562 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 
| 547 DCHECK(!array->map()->is_observed()); | 563 DCHECK(!array->map()->is_observed()); | 
| 548 | 564 | 
| 549 int argument_count = args.length() - 1; | 565 int argument_count = args.length() - 1; | 
| 550 int relative_start = 0; | 566 int relative_start = 0; | 
| 551 if (argument_count > 0) { | 567 if (argument_count > 0) { | 
| 552 DisallowHeapAllocation no_gc; | 568 DisallowHeapAllocation no_gc; | 
| 553 if (!ClampedToInteger(args[1], &relative_start)) { | 569 if (!ClampedToInteger(args[1], &relative_start)) { | 
| 554 AllowHeapAllocation allow_allocation; | 570 AllowHeapAllocation allow_allocation; | 
| 555 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | 571 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | 
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 604 * or a dictionary for sparse array. Since Dictionary is a subtype | 620 * or a dictionary for sparse array. Since Dictionary is a subtype | 
| 605 * of FixedArray, the class can be used by both fast and slow cases. | 621 * of FixedArray, the class can be used by both fast and slow cases. | 
| 606 * The second parameter of the constructor, fast_elements, specifies | 622 * The second parameter of the constructor, fast_elements, specifies | 
| 607 * whether the storage is a FixedArray or Dictionary. | 623 * whether the storage is a FixedArray or Dictionary. | 
| 608 * | 624 * | 
| 609 * An index limit is used to deal with the situation that a result array | 625 * An index limit is used to deal with the situation that a result array | 
| 610 * length overflows 32-bit non-negative integer. | 626 * length overflows 32-bit non-negative integer. | 
| 611 */ | 627 */ | 
| 612 class ArrayConcatVisitor { | 628 class ArrayConcatVisitor { | 
| 613 public: | 629 public: | 
| 614 ArrayConcatVisitor(Isolate* isolate, Handle<FixedArray> storage, | 630 ArrayConcatVisitor(Isolate* isolate, Handle<Object> storage, | 
| 
adamk
2016/01/06 00:10:11
I think you should consider doing the concat stuff
 
Dan Ehrenberg
2016/01/07 00:42:57
Good idea; this patch doesn't include the concat s
 | |
| 615 bool fast_elements) | 631 bool fast_elements) | 
| 616 : isolate_(isolate), | 632 : isolate_(isolate), | 
| 617 storage_(Handle<FixedArray>::cast( | 633 storage_(isolate->global_handles()->Create(*storage)), | 
| 618 isolate->global_handles()->Create(*storage))), | |
| 619 index_offset_(0u), | 634 index_offset_(0u), | 
| 620 bit_field_(FastElementsField::encode(fast_elements) | | 635 bit_field_(FastElementsField::encode(fast_elements) | | 
| 621 ExceedsLimitField::encode(false)) {} | 636 ExceedsLimitField::encode(false) | | 
| 637 IsFixedArrayField::encode(storage->IsFixedArray())) { | |
| 638 DCHECK(!(this->fast_elements() && !is_fixed_array())); | |
| 639 } | |
| 622 | 640 | 
| 623 ~ArrayConcatVisitor() { clear_storage(); } | 641 ~ArrayConcatVisitor() { clear_storage(); } | 
| 624 | 642 | 
| 625 void visit(uint32_t i, Handle<Object> elm) { | 643 bool visit(uint32_t i, Handle<Object> elm) { | 
| 644 uint32_t index = index_offset_ + i; | |
| 645 | |
| 646 if (!is_fixed_array()) { | |
| 647 Handle<Object> element_value; | |
| 648 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 649 isolate_, element_value, | |
| 650 Object::SetElement(isolate_, storage_, index, elm, STRICT), false); | |
| 651 return true; | |
| 652 } | |
| 653 | |
| 626 if (i >= JSObject::kMaxElementCount - index_offset_) { | 654 if (i >= JSObject::kMaxElementCount - index_offset_) { | 
| 627 set_exceeds_array_limit(true); | 655 set_exceeds_array_limit(true); | 
| 628 return; | 656 return true; | 
| 629 } | 657 } | 
| 630 uint32_t index = index_offset_ + i; | |
| 631 | 658 | 
| 632 if (fast_elements()) { | 659 if (fast_elements()) { | 
| 633 if (index < static_cast<uint32_t>(storage_->length())) { | 660 if (index < static_cast<uint32_t>(storage_fixed_array()->length())) { | 
| 634 storage_->set(index, *elm); | 661 storage_fixed_array()->set(index, *elm); | 
| 635 return; | 662 return true; | 
| 636 } | 663 } | 
| 637 // Our initial estimate of length was foiled, possibly by | 664 // Our initial estimate of length was foiled, possibly by | 
| 638 // getters on the arrays increasing the length of later arrays | 665 // getters on the arrays increasing the length of later arrays | 
| 639 // during iteration. | 666 // during iteration. | 
| 640 // This shouldn't happen in anything but pathological cases. | 667 // This shouldn't happen in anything but pathological cases. | 
| 641 SetDictionaryMode(); | 668 SetDictionaryMode(); | 
| 642 // Fall-through to dictionary mode. | 669 // Fall-through to dictionary mode. | 
| 643 } | 670 } | 
| 644 DCHECK(!fast_elements()); | 671 DCHECK(!fast_elements()); | 
| 645 Handle<SeededNumberDictionary> dict( | 672 Handle<SeededNumberDictionary> dict( | 
| 646 SeededNumberDictionary::cast(*storage_)); | 673 SeededNumberDictionary::cast(*storage_)); | 
| 647 // The object holding this backing store has just been allocated, so | 674 // The object holding this backing store has just been allocated, so | 
| 648 // it cannot yet be used as a prototype. | 675 // it cannot yet be used as a prototype. | 
| 649 Handle<SeededNumberDictionary> result = | 676 Handle<SeededNumberDictionary> result = | 
| 650 SeededNumberDictionary::AtNumberPut(dict, index, elm, false); | 677 SeededNumberDictionary::AtNumberPut(dict, index, elm, false); | 
| 651 if (!result.is_identical_to(dict)) { | 678 if (!result.is_identical_to(dict)) { | 
| 652 // Dictionary needed to grow. | 679 // Dictionary needed to grow. | 
| 653 clear_storage(); | 680 clear_storage(); | 
| 654 set_storage(*result); | 681 set_storage(*result); | 
| 655 } | 682 } | 
| 683 return true; | |
| 656 } | 684 } | 
| 657 | 685 | 
| 658 void increase_index_offset(uint32_t delta) { | 686 void increase_index_offset(uint32_t delta) { | 
| 659 if (JSObject::kMaxElementCount - index_offset_ < delta) { | 687 if (JSObject::kMaxElementCount - index_offset_ < delta) { | 
| 660 index_offset_ = JSObject::kMaxElementCount; | 688 index_offset_ = JSObject::kMaxElementCount; | 
| 661 } else { | 689 } else { | 
| 662 index_offset_ += delta; | 690 index_offset_ += delta; | 
| 663 } | 691 } | 
| 664 // If the initial length estimate was off (see special case in visit()), | 692 // If the initial length estimate was off (see special case in visit()), | 
| 665 // but the array blowing the limit didn't contain elements beyond the | 693 // but the array blowing the limit didn't contain elements beyond the | 
| 666 // provided-for index range, go to dictionary mode now. | 694 // provided-for index range, go to dictionary mode now. | 
| 667 if (fast_elements() && | 695 if (fast_elements() && | 
| 668 index_offset_ > | 696 index_offset_ > | 
| 669 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) { | 697 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) { | 
| 670 SetDictionaryMode(); | 698 SetDictionaryMode(); | 
| 671 } | 699 } | 
| 672 } | 700 } | 
| 673 | 701 | 
| 674 bool exceeds_array_limit() const { | 702 bool exceeds_array_limit() const { | 
| 675 return ExceedsLimitField::decode(bit_field_); | 703 return ExceedsLimitField::decode(bit_field_); | 
| 676 } | 704 } | 
| 677 | 705 | 
| 678 Handle<JSArray> ToArray() { | 706 Handle<JSArray> ToArray() { | 
| 707 DCHECK(is_fixed_array()); | |
| 679 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); | 708 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); | 
| 680 Handle<Object> length = | 709 Handle<Object> length = | 
| 681 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); | 710 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); | 
| 682 Handle<Map> map = JSObject::GetElementsTransitionMap( | 711 Handle<Map> map = JSObject::GetElementsTransitionMap( | 
| 683 array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); | 712 array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); | 
| 684 array->set_map(*map); | 713 array->set_map(*map); | 
| 685 array->set_length(*length); | 714 array->set_length(*length); | 
| 686 array->set_elements(*storage_); | 715 array->set_elements(*storage_fixed_array()); | 
| 687 return array; | 716 return array; | 
| 688 } | 717 } | 
| 689 | 718 | 
| 719 // Storage is either a FixedArray (if is_fixed_array()) or a JSReciever | |
| 720 // (otherwise) | |
| 721 Handle<FixedArray> storage_fixed_array() { | |
| 722 DCHECK(is_fixed_array()); | |
| 723 return Handle<FixedArray>::cast(storage_); | |
| 724 } | |
| 725 Handle<JSReceiver> storage_jsreceiver() { | |
| 726 DCHECK(!is_fixed_array()); | |
| 727 return Handle<JSReceiver>::cast(storage_); | |
| 728 } | |
| 729 | |
| 690 private: | 730 private: | 
| 691 // Convert storage to dictionary mode. | 731 // Convert storage to dictionary mode. | 
| 692 void SetDictionaryMode() { | 732 void SetDictionaryMode() { | 
| 693 DCHECK(fast_elements()); | 733 DCHECK(fast_elements() && is_fixed_array()); | 
| 694 Handle<FixedArray> current_storage(*storage_); | 734 Handle<FixedArray> current_storage = storage_fixed_array(); | 
| 695 Handle<SeededNumberDictionary> slow_storage( | 735 Handle<SeededNumberDictionary> slow_storage( | 
| 696 SeededNumberDictionary::New(isolate_, current_storage->length())); | 736 SeededNumberDictionary::New(isolate_, current_storage->length())); | 
| 697 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); | 737 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); | 
| 698 for (uint32_t i = 0; i < current_length; i++) { | 738 for (uint32_t i = 0; i < current_length; i++) { | 
| 699 HandleScope loop_scope(isolate_); | 739 HandleScope loop_scope(isolate_); | 
| 700 Handle<Object> element(current_storage->get(i), isolate_); | 740 Handle<Object> element(current_storage->get(i), isolate_); | 
| 701 if (!element->IsTheHole()) { | 741 if (!element->IsTheHole()) { | 
| 702 // The object holding this backing store has just been allocated, so | 742 // The object holding this backing store has just been allocated, so | 
| 703 // it cannot yet be used as a prototype. | 743 // it cannot yet be used as a prototype. | 
| 704 Handle<SeededNumberDictionary> new_storage = | 744 Handle<SeededNumberDictionary> new_storage = | 
| 705 SeededNumberDictionary::AtNumberPut(slow_storage, i, element, | 745 SeededNumberDictionary::AtNumberPut(slow_storage, i, element, | 
| 706 false); | 746 false); | 
| 707 if (!new_storage.is_identical_to(slow_storage)) { | 747 if (!new_storage.is_identical_to(slow_storage)) { | 
| 708 slow_storage = loop_scope.CloseAndEscape(new_storage); | 748 slow_storage = loop_scope.CloseAndEscape(new_storage); | 
| 709 } | 749 } | 
| 710 } | 750 } | 
| 711 } | 751 } | 
| 712 clear_storage(); | 752 clear_storage(); | 
| 713 set_storage(*slow_storage); | 753 set_storage(*slow_storage); | 
| 714 set_fast_elements(false); | 754 set_fast_elements(false); | 
| 715 } | 755 } | 
| 716 | 756 | 
| 717 inline void clear_storage() { | 757 inline void clear_storage() { | 
| 718 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location()); | 758 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location()); | 
| 719 } | 759 } | 
| 720 | 760 | 
| 721 inline void set_storage(FixedArray* storage) { | 761 inline void set_storage(FixedArray* storage) { | 
| 722 storage_ = | 762 DCHECK(is_fixed_array()); | 
| 723 Handle<FixedArray>::cast(isolate_->global_handles()->Create(storage)); | 763 storage_ = isolate_->global_handles()->Create(storage); | 
| 724 } | 764 } | 
| 725 | 765 | 
| 726 class FastElementsField : public BitField<bool, 0, 1> {}; | 766 class FastElementsField : public BitField<bool, 0, 1> {}; | 
| 727 class ExceedsLimitField : public BitField<bool, 1, 1> {}; | 767 class ExceedsLimitField : public BitField<bool, 1, 1> {}; | 
| 768 class IsFixedArrayField : public BitField<bool, 2, 1> {}; | |
| 728 | 769 | 
| 729 bool fast_elements() const { return FastElementsField::decode(bit_field_); } | 770 bool fast_elements() const { return FastElementsField::decode(bit_field_); } | 
| 730 void set_fast_elements(bool fast) { | 771 void set_fast_elements(bool fast) { | 
| 731 bit_field_ = FastElementsField::update(bit_field_, fast); | 772 bit_field_ = FastElementsField::update(bit_field_, fast); | 
| 732 } | 773 } | 
| 733 void set_exceeds_array_limit(bool exceeds) { | 774 void set_exceeds_array_limit(bool exceeds) { | 
| 734 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds); | 775 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds); | 
| 735 } | 776 } | 
| 777 bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); } | |
| 736 | 778 | 
| 737 Isolate* isolate_; | 779 Isolate* isolate_; | 
| 738 Handle<FixedArray> storage_; // Always a global handle. | 780 Handle<Object> storage_; // Always a global handle. | 
| 739 // Index after last seen index. Always less than or equal to | 781 // Index after last seen index. Always less than or equal to | 
| 740 // JSObject::kMaxElementCount. | 782 // JSObject::kMaxElementCount. | 
| 741 uint32_t index_offset_; | 783 uint32_t index_offset_; | 
| 742 uint32_t bit_field_; | 784 uint32_t bit_field_; | 
| 743 }; | 785 }; | 
| 744 | 786 | 
| 745 | 787 | 
| 746 uint32_t EstimateElementCount(Handle<JSArray> array) { | 788 uint32_t EstimateElementCount(Handle<JSArray> array) { | 
| 747 uint32_t length = static_cast<uint32_t>(array->length()->Number()); | 789 uint32_t length = static_cast<uint32_t>(array->length()->Number()); | 
| 748 int element_count = 0; | 790 int element_count = 0; | 
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 799 // External arrays are always dense. | 841 // External arrays are always dense. | 
| 800 return length; | 842 return length; | 
| 801 } | 843 } | 
| 802 // As an estimate, we assume that the prototype doesn't contain any | 844 // As an estimate, we assume that the prototype doesn't contain any | 
| 803 // inherited elements. | 845 // inherited elements. | 
| 804 return element_count; | 846 return element_count; | 
| 805 } | 847 } | 
| 806 | 848 | 
| 807 | 849 | 
| 808 template <class ExternalArrayClass, class ElementType> | 850 template <class ExternalArrayClass, class ElementType> | 
| 809 void IterateTypedArrayElements(Isolate* isolate, Handle<JSObject> receiver, | 851 bool IterateTypedArrayElements(Isolate* isolate, Handle<JSObject> receiver, | 
| 810 bool elements_are_ints, | 852 bool elements_are_ints, | 
| 811 bool elements_are_guaranteed_smis, | 853 bool elements_are_guaranteed_smis, | 
| 812 ArrayConcatVisitor* visitor) { | 854 ArrayConcatVisitor* visitor) { | 
| 813 Handle<ExternalArrayClass> array( | 855 Handle<ExternalArrayClass> array( | 
| 814 ExternalArrayClass::cast(receiver->elements())); | 856 ExternalArrayClass::cast(receiver->elements())); | 
| 815 uint32_t len = static_cast<uint32_t>(array->length()); | 857 uint32_t len = static_cast<uint32_t>(array->length()); | 
| 816 | 858 | 
| 817 DCHECK(visitor != NULL); | 859 DCHECK(visitor != NULL); | 
| 818 if (elements_are_ints) { | 860 if (elements_are_ints) { | 
| 819 if (elements_are_guaranteed_smis) { | 861 if (elements_are_guaranteed_smis) { | 
| 820 for (uint32_t j = 0; j < len; j++) { | 862 for (uint32_t j = 0; j < len; j++) { | 
| 821 HandleScope loop_scope(isolate); | 863 HandleScope loop_scope(isolate); | 
| 822 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))), | 864 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))), | 
| 823 isolate); | 865 isolate); | 
| 824 visitor->visit(j, e); | 866 if (!visitor->visit(j, e)) return false; | 
| 825 } | 867 } | 
| 826 } else { | 868 } else { | 
| 827 for (uint32_t j = 0; j < len; j++) { | 869 for (uint32_t j = 0; j < len; j++) { | 
| 828 HandleScope loop_scope(isolate); | 870 HandleScope loop_scope(isolate); | 
| 829 int64_t val = static_cast<int64_t>(array->get_scalar(j)); | 871 int64_t val = static_cast<int64_t>(array->get_scalar(j)); | 
| 830 if (Smi::IsValid(static_cast<intptr_t>(val))) { | 872 if (Smi::IsValid(static_cast<intptr_t>(val))) { | 
| 831 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate); | 873 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate); | 
| 832 visitor->visit(j, e); | 874 if (!visitor->visit(j, e)) return false; | 
| 833 } else { | 875 } else { | 
| 834 Handle<Object> e = | 876 Handle<Object> e = | 
| 835 isolate->factory()->NewNumber(static_cast<ElementType>(val)); | 877 isolate->factory()->NewNumber(static_cast<ElementType>(val)); | 
| 836 visitor->visit(j, e); | 878 if (!visitor->visit(j, e)) return false; | 
| 837 } | 879 } | 
| 838 } | 880 } | 
| 839 } | 881 } | 
| 840 } else { | 882 } else { | 
| 841 for (uint32_t j = 0; j < len; j++) { | 883 for (uint32_t j = 0; j < len; j++) { | 
| 842 HandleScope loop_scope(isolate); | 884 HandleScope loop_scope(isolate); | 
| 843 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j)); | 885 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j)); | 
| 844 visitor->visit(j, e); | 886 if (!visitor->visit(j, e)) return false; | 
| 845 } | 887 } | 
| 846 } | 888 } | 
| 889 return true; | |
| 847 } | 890 } | 
| 848 | 891 | 
| 849 | 892 | 
| 850 // Used for sorting indices in a List<uint32_t>. | 893 // Used for sorting indices in a List<uint32_t>. | 
| 851 int compareUInt32(const uint32_t* ap, const uint32_t* bp) { | 894 int compareUInt32(const uint32_t* ap, const uint32_t* bp) { | 
| 852 uint32_t a = *ap; | 895 uint32_t a = *ap; | 
| 853 uint32_t b = *bp; | 896 uint32_t b = *bp; | 
| 854 return (a == b) ? 0 : (a < b) ? -1 : 1; | 897 return (a == b) ? 0 : (a < b) ? -1 : 1; | 
| 855 } | 898 } | 
| 856 | 899 | 
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 953 uint32_t length, ArrayConcatVisitor* visitor) { | 996 uint32_t length, ArrayConcatVisitor* visitor) { | 
| 954 for (uint32_t i = 0; i < length; ++i) { | 997 for (uint32_t i = 0; i < length; ++i) { | 
| 955 HandleScope loop_scope(isolate); | 998 HandleScope loop_scope(isolate); | 
| 956 Maybe<bool> maybe = JSReceiver::HasElement(receiver, i); | 999 Maybe<bool> maybe = JSReceiver::HasElement(receiver, i); | 
| 957 if (!maybe.IsJust()) return false; | 1000 if (!maybe.IsJust()) return false; | 
| 958 if (maybe.FromJust()) { | 1001 if (maybe.FromJust()) { | 
| 959 Handle<Object> element_value; | 1002 Handle<Object> element_value; | 
| 960 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_value, | 1003 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_value, | 
| 961 Object::GetElement(isolate, receiver, i), | 1004 Object::GetElement(isolate, receiver, i), | 
| 962 false); | 1005 false); | 
| 963 visitor->visit(i, element_value); | 1006 if (!visitor->visit(i, element_value)) return false; | 
| 964 } | 1007 } | 
| 965 } | 1008 } | 
| 966 visitor->increase_index_offset(length); | 1009 visitor->increase_index_offset(length); | 
| 967 return true; | 1010 return true; | 
| 968 } | 1011 } | 
| 969 | 1012 | 
| 970 | 1013 | 
| 971 /** | 1014 /** | 
| 972 * A helper function that visits "array" elements of a JSReceiver in numerical | 1015 * A helper function that visits "array" elements of a JSReceiver in numerical | 
| 973 * order. | 1016 * order. | 
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1013 case FAST_HOLEY_ELEMENTS: { | 1056 case FAST_HOLEY_ELEMENTS: { | 
| 1014 // Run through the elements FixedArray and use HasElement and GetElement | 1057 // Run through the elements FixedArray and use HasElement and GetElement | 
| 1015 // to check the prototype for missing elements. | 1058 // to check the prototype for missing elements. | 
| 1016 Handle<FixedArray> elements(FixedArray::cast(array->elements())); | 1059 Handle<FixedArray> elements(FixedArray::cast(array->elements())); | 
| 1017 int fast_length = static_cast<int>(length); | 1060 int fast_length = static_cast<int>(length); | 
| 1018 DCHECK(fast_length <= elements->length()); | 1061 DCHECK(fast_length <= elements->length()); | 
| 1019 for (int j = 0; j < fast_length; j++) { | 1062 for (int j = 0; j < fast_length; j++) { | 
| 1020 HandleScope loop_scope(isolate); | 1063 HandleScope loop_scope(isolate); | 
| 1021 Handle<Object> element_value(elements->get(j), isolate); | 1064 Handle<Object> element_value(elements->get(j), isolate); | 
| 1022 if (!element_value->IsTheHole()) { | 1065 if (!element_value->IsTheHole()) { | 
| 1023 visitor->visit(j, element_value); | 1066 if (!visitor->visit(j, element_value)) return false; | 
| 1024 } else { | 1067 } else { | 
| 1025 Maybe<bool> maybe = JSReceiver::HasElement(array, j); | 1068 Maybe<bool> maybe = JSReceiver::HasElement(array, j); | 
| 1026 if (!maybe.IsJust()) return false; | 1069 if (!maybe.IsJust()) return false; | 
| 1027 if (maybe.FromJust()) { | 1070 if (maybe.FromJust()) { | 
| 1028 // Call GetElement on array, not its prototype, or getters won't | 1071 // Call GetElement on array, not its prototype, or getters won't | 
| 1029 // have the correct receiver. | 1072 // have the correct receiver. | 
| 1030 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 1073 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 
| 1031 isolate, element_value, Object::GetElement(isolate, array, j), | 1074 isolate, element_value, Object::GetElement(isolate, array, j), | 
| 1032 false); | 1075 false); | 
| 1033 visitor->visit(j, element_value); | 1076 if (!visitor->visit(j, element_value)) return false; | 
| 1034 } | 1077 } | 
| 1035 } | 1078 } | 
| 1036 } | 1079 } | 
| 1037 break; | 1080 break; | 
| 1038 } | 1081 } | 
| 1039 case FAST_HOLEY_DOUBLE_ELEMENTS: | 1082 case FAST_HOLEY_DOUBLE_ELEMENTS: | 
| 1040 case FAST_DOUBLE_ELEMENTS: { | 1083 case FAST_DOUBLE_ELEMENTS: { | 
| 1041 // Empty array is FixedArray but not FixedDoubleArray. | 1084 // Empty array is FixedArray but not FixedDoubleArray. | 
| 1042 if (length == 0) break; | 1085 if (length == 0) break; | 
| 1043 // Run through the elements FixedArray and use HasElement and GetElement | 1086 // Run through the elements FixedArray and use HasElement and GetElement | 
| 1044 // to check the prototype for missing elements. | 1087 // to check the prototype for missing elements. | 
| 1045 if (array->elements()->IsFixedArray()) { | 1088 if (array->elements()->IsFixedArray()) { | 
| 1046 DCHECK(array->elements()->length() == 0); | 1089 DCHECK(array->elements()->length() == 0); | 
| 1047 break; | 1090 break; | 
| 1048 } | 1091 } | 
| 1049 Handle<FixedDoubleArray> elements( | 1092 Handle<FixedDoubleArray> elements( | 
| 1050 FixedDoubleArray::cast(array->elements())); | 1093 FixedDoubleArray::cast(array->elements())); | 
| 1051 int fast_length = static_cast<int>(length); | 1094 int fast_length = static_cast<int>(length); | 
| 1052 DCHECK(fast_length <= elements->length()); | 1095 DCHECK(fast_length <= elements->length()); | 
| 1053 for (int j = 0; j < fast_length; j++) { | 1096 for (int j = 0; j < fast_length; j++) { | 
| 1054 HandleScope loop_scope(isolate); | 1097 HandleScope loop_scope(isolate); | 
| 1055 if (!elements->is_the_hole(j)) { | 1098 if (!elements->is_the_hole(j)) { | 
| 1056 double double_value = elements->get_scalar(j); | 1099 double double_value = elements->get_scalar(j); | 
| 1057 Handle<Object> element_value = | 1100 Handle<Object> element_value = | 
| 1058 isolate->factory()->NewNumber(double_value); | 1101 isolate->factory()->NewNumber(double_value); | 
| 1059 visitor->visit(j, element_value); | 1102 if (!visitor->visit(j, element_value)) return false; | 
| 1060 } else { | 1103 } else { | 
| 1061 Maybe<bool> maybe = JSReceiver::HasElement(array, j); | 1104 Maybe<bool> maybe = JSReceiver::HasElement(array, j); | 
| 1062 if (!maybe.IsJust()) return false; | 1105 if (!maybe.IsJust()) return false; | 
| 1063 if (maybe.FromJust()) { | 1106 if (maybe.FromJust()) { | 
| 1064 // Call GetElement on array, not its prototype, or getters won't | 1107 // Call GetElement on array, not its prototype, or getters won't | 
| 1065 // have the correct receiver. | 1108 // have the correct receiver. | 
| 1066 Handle<Object> element_value; | 1109 Handle<Object> element_value; | 
| 1067 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 1110 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 
| 1068 isolate, element_value, Object::GetElement(isolate, array, j), | 1111 isolate, element_value, Object::GetElement(isolate, array, j), | 
| 1069 false); | 1112 false); | 
| 1070 visitor->visit(j, element_value); | 1113 if (!visitor->visit(j, element_value)) return false; | 
| 1071 } | 1114 } | 
| 1072 } | 1115 } | 
| 1073 } | 1116 } | 
| 1074 break; | 1117 break; | 
| 1075 } | 1118 } | 
| 1076 case DICTIONARY_ELEMENTS: { | 1119 case DICTIONARY_ELEMENTS: { | 
| 1077 // CollectElementIndices() can't be called when there's a JSProxy | 1120 // CollectElementIndices() can't be called when there's a JSProxy | 
| 1078 // on the prototype chain. | 1121 // on the prototype chain. | 
| 1079 for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd(); | 1122 for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd(); | 
| 1080 iter.Advance()) { | 1123 iter.Advance()) { | 
| 1081 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | 1124 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | 
| 1082 return IterateElementsSlow(isolate, array, length, visitor); | 1125 return IterateElementsSlow(isolate, array, length, visitor); | 
| 1083 } | 1126 } | 
| 1084 } | 1127 } | 
| 1085 Handle<SeededNumberDictionary> dict(array->element_dictionary()); | 1128 Handle<SeededNumberDictionary> dict(array->element_dictionary()); | 
| 1086 List<uint32_t> indices(dict->Capacity() / 2); | 1129 List<uint32_t> indices(dict->Capacity() / 2); | 
| 1087 // Collect all indices in the object and the prototypes less | 1130 // Collect all indices in the object and the prototypes less | 
| 1088 // than length. This might introduce duplicates in the indices list. | 1131 // than length. This might introduce duplicates in the indices list. | 
| 1089 CollectElementIndices(array, length, &indices); | 1132 CollectElementIndices(array, length, &indices); | 
| 1090 indices.Sort(&compareUInt32); | 1133 indices.Sort(&compareUInt32); | 
| 1091 int j = 0; | 1134 int j = 0; | 
| 1092 int n = indices.length(); | 1135 int n = indices.length(); | 
| 1093 while (j < n) { | 1136 while (j < n) { | 
| 1094 HandleScope loop_scope(isolate); | 1137 HandleScope loop_scope(isolate); | 
| 1095 uint32_t index = indices[j]; | 1138 uint32_t index = indices[j]; | 
| 1096 Handle<Object> element; | 1139 Handle<Object> element; | 
| 1097 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 1140 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 
| 1098 isolate, element, Object::GetElement(isolate, array, index), false); | 1141 isolate, element, Object::GetElement(isolate, array, index), false); | 
| 1099 visitor->visit(index, element); | 1142 if (!visitor->visit(index, element)) return false; | 
| 1100 // Skip to next different index (i.e., omit duplicates). | 1143 // Skip to next different index (i.e., omit duplicates). | 
| 1101 do { | 1144 do { | 
| 1102 j++; | 1145 j++; | 
| 1103 } while (j < n && indices[j] == index); | 1146 } while (j < n && indices[j] == index); | 
| 1104 } | 1147 } | 
| 1105 break; | 1148 break; | 
| 1106 } | 1149 } | 
| 1107 case UINT8_CLAMPED_ELEMENTS: { | 1150 case UINT8_CLAMPED_ELEMENTS: { | 
| 1108 Handle<FixedUint8ClampedArray> pixels( | 1151 Handle<FixedUint8ClampedArray> pixels( | 
| 1109 FixedUint8ClampedArray::cast(array->elements())); | 1152 FixedUint8ClampedArray::cast(array->elements())); | 
| 1110 for (uint32_t j = 0; j < length; j++) { | 1153 for (uint32_t j = 0; j < length; j++) { | 
| 1111 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); | 1154 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); | 
| 1112 visitor->visit(j, e); | 1155 visitor->visit(j, e); | 
| 1113 } | 1156 } | 
| 1114 break; | 1157 break; | 
| 1115 } | 1158 } | 
| 1116 case INT8_ELEMENTS: { | 1159 case INT8_ELEMENTS: { | 
| 1117 IterateTypedArrayElements<FixedInt8Array, int8_t>(isolate, array, true, | 1160 if (!IterateTypedArrayElements<FixedInt8Array, int8_t>( | 
| 1118 true, visitor); | 1161 isolate, array, true, true, visitor)) | 
| 1162 return false; | |
| 1119 break; | 1163 break; | 
| 1120 } | 1164 } | 
| 1121 case UINT8_ELEMENTS: { | 1165 case UINT8_ELEMENTS: { | 
| 1122 IterateTypedArrayElements<FixedUint8Array, uint8_t>(isolate, array, true, | 1166 if (!IterateTypedArrayElements<FixedUint8Array, uint8_t>( | 
| 1123 true, visitor); | 1167 isolate, array, true, true, visitor)) | 
| 1168 return false; | |
| 1124 break; | 1169 break; | 
| 1125 } | 1170 } | 
| 1126 case INT16_ELEMENTS: { | 1171 case INT16_ELEMENTS: { | 
| 1127 IterateTypedArrayElements<FixedInt16Array, int16_t>(isolate, array, true, | 1172 if (!IterateTypedArrayElements<FixedInt16Array, int16_t>( | 
| 1128 true, visitor); | 1173 isolate, array, true, true, visitor)) | 
| 1174 return false; | |
| 1129 break; | 1175 break; | 
| 1130 } | 1176 } | 
| 1131 case UINT16_ELEMENTS: { | 1177 case UINT16_ELEMENTS: { | 
| 1132 IterateTypedArrayElements<FixedUint16Array, uint16_t>( | 1178 if (!IterateTypedArrayElements<FixedUint16Array, uint16_t>( | 
| 1133 isolate, array, true, true, visitor); | 1179 isolate, array, true, true, visitor)) | 
| 1180 return false; | |
| 1134 break; | 1181 break; | 
| 1135 } | 1182 } | 
| 1136 case INT32_ELEMENTS: { | 1183 case INT32_ELEMENTS: { | 
| 1137 IterateTypedArrayElements<FixedInt32Array, int32_t>(isolate, array, true, | 1184 if (!IterateTypedArrayElements<FixedInt32Array, int32_t>( | 
| 1138 false, visitor); | 1185 isolate, array, true, false, visitor)) | 
| 1186 return false; | |
| 1139 break; | 1187 break; | 
| 1140 } | 1188 } | 
| 1141 case UINT32_ELEMENTS: { | 1189 case UINT32_ELEMENTS: { | 
| 1142 IterateTypedArrayElements<FixedUint32Array, uint32_t>( | 1190 if (!IterateTypedArrayElements<FixedUint32Array, uint32_t>( | 
| 1143 isolate, array, true, false, visitor); | 1191 isolate, array, true, false, visitor)) | 
| 1192 return false; | |
| 1144 break; | 1193 break; | 
| 1145 } | 1194 } | 
| 1146 case FLOAT32_ELEMENTS: { | 1195 case FLOAT32_ELEMENTS: { | 
| 1147 IterateTypedArrayElements<FixedFloat32Array, float>(isolate, array, false, | 1196 if (!IterateTypedArrayElements<FixedFloat32Array, float>( | 
| 1148 false, visitor); | 1197 isolate, array, false, false, visitor)) | 
| 1198 return false; | |
| 1149 break; | 1199 break; | 
| 1150 } | 1200 } | 
| 1151 case FLOAT64_ELEMENTS: { | 1201 case FLOAT64_ELEMENTS: { | 
| 1152 IterateTypedArrayElements<FixedFloat64Array, double>( | 1202 if (!IterateTypedArrayElements<FixedFloat64Array, double>( | 
| 1153 isolate, array, false, false, visitor); | 1203 isolate, array, false, false, visitor)) | 
| 1204 return false; | |
| 1154 break; | 1205 break; | 
| 1155 } | 1206 } | 
| 1156 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: | 1207 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: | 
| 1157 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { | 1208 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { | 
| 1158 for (uint32_t index = 0; index < length; index++) { | 1209 for (uint32_t index = 0; index < length; index++) { | 
| 1159 HandleScope loop_scope(isolate); | 1210 HandleScope loop_scope(isolate); | 
| 1160 Handle<Object> element; | 1211 Handle<Object> element; | 
| 1161 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 1212 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 
| 1162 isolate, element, Object::GetElement(isolate, array, index), false); | 1213 isolate, element, Object::GetElement(isolate, array, index), false); | 
| 1163 visitor->visit(index, element); | 1214 if (!visitor->visit(index, element)) return false; | 
| 1164 } | 1215 } | 
| 1165 break; | 1216 break; | 
| 1166 } | 1217 } | 
| 1167 } | 1218 } | 
| 1168 visitor->increase_index_offset(length); | 1219 visitor->increase_index_offset(length); | 
| 1169 return true; | 1220 return true; | 
| 1170 } | 1221 } | 
| 1171 | 1222 | 
| 1172 | 1223 | 
| 1173 bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { | 1224 bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { | 
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1187 Handle<Object> value; | 1238 Handle<Object> value; | 
| 1188 MaybeHandle<Object> maybeValue = | 1239 MaybeHandle<Object> maybeValue = | 
| 1189 i::Runtime::GetObjectProperty(isolate, obj, key); | 1240 i::Runtime::GetObjectProperty(isolate, obj, key); | 
| 1190 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); | 1241 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); | 
| 1191 if (!value->IsUndefined()) return Just(value->BooleanValue()); | 1242 if (!value->IsUndefined()) return Just(value->BooleanValue()); | 
| 1192 } | 1243 } | 
| 1193 return Object::IsArray(obj); | 1244 return Object::IsArray(obj); | 
| 1194 } | 1245 } | 
| 1195 | 1246 | 
| 1196 | 1247 | 
| 1197 Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) { | 1248 Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, | 
| 1249 Isolate* isolate) { | |
| 1198 int argument_count = args->length(); | 1250 int argument_count = args->length(); | 
| 1199 | 1251 | 
| 1252 bool array_species = *species == isolate->context()->array_function(); | |
| 1253 | |
| 1200 // Pass 1: estimate the length and number of elements of the result. | 1254 // Pass 1: estimate the length and number of elements of the result. | 
| 1201 // The actual length can be larger if any of the arguments have getters | 1255 // The actual length can be larger if any of the arguments have getters | 
| 1202 // that mutate other arguments (but will otherwise be precise). | 1256 // that mutate other arguments (but will otherwise be precise). | 
| 1203 // The number of elements is precise if there are no inherited elements. | 1257 // The number of elements is precise if there are no inherited elements. | 
| 1204 | 1258 | 
| 1205 ElementsKind kind = FAST_SMI_ELEMENTS; | 1259 ElementsKind kind = FAST_SMI_ELEMENTS; | 
| 1206 | 1260 | 
| 1207 uint32_t estimate_result_length = 0; | 1261 uint32_t estimate_result_length = 0; | 
| 1208 uint32_t estimate_nof_elements = 0; | 1262 uint32_t estimate_nof_elements = 0; | 
| 1209 for (int i = 0; i < argument_count; i++) { | 1263 for (int i = 0; i < argument_count; i++) { | 
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1240 if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) { | 1294 if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) { | 
| 1241 estimate_nof_elements = JSObject::kMaxElementCount; | 1295 estimate_nof_elements = JSObject::kMaxElementCount; | 
| 1242 } else { | 1296 } else { | 
| 1243 estimate_nof_elements += element_estimate; | 1297 estimate_nof_elements += element_estimate; | 
| 1244 } | 1298 } | 
| 1245 } | 1299 } | 
| 1246 | 1300 | 
| 1247 // If estimated number of elements is more than half of length, a | 1301 // If estimated number of elements is more than half of length, a | 
| 1248 // fixed array (fast case) is more time and space-efficient than a | 1302 // fixed array (fast case) is more time and space-efficient than a | 
| 1249 // dictionary. | 1303 // dictionary. | 
| 1250 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; | 1304 bool fast_case = | 
| 1305 array_species && (estimate_nof_elements * 2) >= estimate_result_length; | |
| 1251 | 1306 | 
| 1252 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) { | 1307 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) { | 
| 1253 Handle<FixedArrayBase> storage = | 1308 Handle<FixedArrayBase> storage = | 
| 1254 isolate->factory()->NewFixedDoubleArray(estimate_result_length); | 1309 isolate->factory()->NewFixedDoubleArray(estimate_result_length); | 
| 1255 int j = 0; | 1310 int j = 0; | 
| 1256 bool failure = false; | 1311 bool failure = false; | 
| 1257 if (estimate_result_length > 0) { | 1312 if (estimate_result_length > 0) { | 
| 1258 Handle<FixedDoubleArray> double_storage = | 1313 Handle<FixedDoubleArray> double_storage = | 
| 1259 Handle<FixedDoubleArray>::cast(storage); | 1314 Handle<FixedDoubleArray>::cast(storage); | 
| 1260 for (int i = 0; i < argument_count; i++) { | 1315 for (int i = 0; i < argument_count; i++) { | 
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1324 Handle<Map> map; | 1379 Handle<Map> map; | 
| 1325 map = JSObject::GetElementsTransitionMap(array, kind); | 1380 map = JSObject::GetElementsTransitionMap(array, kind); | 
| 1326 array->set_map(*map); | 1381 array->set_map(*map); | 
| 1327 array->set_length(length); | 1382 array->set_length(length); | 
| 1328 array->set_elements(*storage); | 1383 array->set_elements(*storage); | 
| 1329 return *array; | 1384 return *array; | 
| 1330 } | 1385 } | 
| 1331 // In case of failure, fall through. | 1386 // In case of failure, fall through. | 
| 1332 } | 1387 } | 
| 1333 | 1388 | 
| 1334 Handle<FixedArray> storage; | 1389 Handle<Object> storage; | 
| 1335 if (fast_case) { | 1390 if (fast_case) { | 
| 1336 // The backing storage array must have non-existing elements to preserve | 1391 // The backing storage array must have non-existing elements to preserve | 
| 1337 // holes across concat operations. | 1392 // holes across concat operations. | 
| 1338 storage = | 1393 storage = | 
| 1339 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); | 1394 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); | 
| 1340 } else { | 1395 } else if (array_species) { | 
| 1341 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate | 1396 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate | 
| 1342 uint32_t at_least_space_for = | 1397 uint32_t at_least_space_for = | 
| 1343 estimate_nof_elements + (estimate_nof_elements >> 2); | 1398 estimate_nof_elements + (estimate_nof_elements >> 2); | 
| 1344 storage = Handle<FixedArray>::cast( | 1399 storage = SeededNumberDictionary::New(isolate, at_least_space_for); | 
| 1345 SeededNumberDictionary::New(isolate, at_least_space_for)); | 1400 } else { | 
| 1401 DCHECK(species->IsConstructor()); | |
| 1402 Handle<Object> length(Smi::FromInt(0), isolate); | |
| 1403 Handle<Object> storage_object; | |
| 1404 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1405 isolate, storage_object, | |
| 1406 Execution::New(isolate, species, species, 1, &length)); | |
| 1407 storage = storage_object; | |
| 1346 } | 1408 } | 
| 1347 | 1409 | 
| 1348 ArrayConcatVisitor visitor(isolate, storage, fast_case); | 1410 ArrayConcatVisitor visitor(isolate, storage, fast_case); | 
| 1349 | 1411 | 
| 1350 for (int i = 0; i < argument_count; i++) { | 1412 for (int i = 0; i < argument_count; i++) { | 
| 1351 Handle<Object> obj((*args)[i], isolate); | 1413 Handle<Object> obj((*args)[i], isolate); | 
| 1352 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj); | 1414 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj); | 
| 1353 MAYBE_RETURN(spreadable, isolate->heap()->exception()); | 1415 MAYBE_RETURN(spreadable, isolate->heap()->exception()); | 
| 1354 if (spreadable.FromJust()) { | 1416 if (spreadable.FromJust()) { | 
| 1355 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj); | 1417 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj); | 
| 1356 if (!IterateElements(isolate, object, &visitor)) { | 1418 if (!IterateElements(isolate, object, &visitor)) { | 
| 1357 return isolate->heap()->exception(); | 1419 return isolate->heap()->exception(); | 
| 1358 } | 1420 } | 
| 1359 } else { | 1421 } else { | 
| 1360 visitor.visit(0, obj); | 1422 visitor.visit(0, obj); | 
| 1361 visitor.increase_index_offset(1); | 1423 visitor.increase_index_offset(1); | 
| 1362 } | 1424 } | 
| 1363 } | 1425 } | 
| 1364 | 1426 | 
| 1365 if (visitor.exceeds_array_limit()) { | 1427 if (visitor.exceeds_array_limit()) { | 
| 1366 THROW_NEW_ERROR_RETURN_FAILURE( | 1428 THROW_NEW_ERROR_RETURN_FAILURE( | 
| 1367 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); | 1429 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); | 
| 1368 } | 1430 } | 
| 1369 return *visitor.ToArray(); | 1431 | 
| 1432 if (array_species) { | |
| 1433 return *visitor.ToArray(); | |
| 1434 } else { | |
| 1435 return *visitor.storage_jsreceiver(); | |
| 1436 } | |
| 1370 } | 1437 } | 
| 1371 | 1438 | 
| 1372 | 1439 | 
| 1373 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { | 1440 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { | 
| 1374 if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) { | 1441 if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) { | 
| 1375 return MaybeHandle<JSArray>(); | 1442 return MaybeHandle<JSArray>(); | 
| 1376 } | 1443 } | 
| 1377 int n_arguments = args->length(); | 1444 int n_arguments = args->length(); | 
| 1378 int result_len = 0; | 1445 int result_len = 0; | 
| 1379 { | 1446 { | 
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1420 if (!Object::ToObject(isolate, handle(args[0], isolate)) | 1487 if (!Object::ToObject(isolate, handle(args[0], isolate)) | 
| 1421 .ToHandle(&receiver)) { | 1488 .ToHandle(&receiver)) { | 
| 1422 THROW_NEW_ERROR_RETURN_FAILURE( | 1489 THROW_NEW_ERROR_RETURN_FAILURE( | 
| 1423 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, | 1490 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, | 
| 1424 isolate->factory()->NewStringFromAsciiChecked( | 1491 isolate->factory()->NewStringFromAsciiChecked( | 
| 1425 "Array.prototype.concat"))); | 1492 "Array.prototype.concat"))); | 
| 1426 } | 1493 } | 
| 1427 args[0] = *receiver; | 1494 args[0] = *receiver; | 
| 1428 | 1495 | 
| 1429 Handle<JSArray> result_array; | 1496 Handle<JSArray> result_array; | 
| 1430 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { | 1497 | 
| 1431 return *result_array; | 1498 // Reading @@species happens before anything else with a side effect, so | 
| 1499 // we can do it here to determine whether to take the fast path. | |
| 1500 Handle<Object> species; | |
| 1501 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1502 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); | |
| 1503 if (*species == isolate->context()->native_context()->array_function()) { | |
| 1504 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { | |
| 1505 return *result_array; | |
| 1506 } | |
| 1507 if (isolate->has_pending_exception()) return isolate->heap()->exception(); | |
| 1432 } | 1508 } | 
| 1433 if (isolate->has_pending_exception()) return isolate->heap()->exception(); | 1509 return Slow_ArrayConcat(&args, species, isolate); | 
| 1434 return Slow_ArrayConcat(&args, isolate); | |
| 1435 } | 1510 } | 
| 1436 | 1511 | 
| 1437 | 1512 | 
| 1438 // ES6 22.1.2.2 Array.isArray | 1513 // ES6 22.1.2.2 Array.isArray | 
| 1439 BUILTIN(ArrayIsArray) { | 1514 BUILTIN(ArrayIsArray) { | 
| 1440 HandleScope scope(isolate); | 1515 HandleScope scope(isolate); | 
| 1441 DCHECK_EQ(2, args.length()); | 1516 DCHECK_EQ(2, args.length()); | 
| 1442 Handle<Object> object = args.at<Object>(1); | 1517 Handle<Object> object = args.at<Object>(1); | 
| 1443 Maybe<bool> result = Object::IsArray(object); | 1518 Maybe<bool> result = Object::IsArray(object); | 
| 1444 MAYBE_RETURN(result, isolate->heap()->exception()); | 1519 MAYBE_RETURN(result, isolate->heap()->exception()); | 
| (...skipping 1848 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3293 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 3368 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 
| 3294 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 3369 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 
| 3295 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 3370 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 
| 3296 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 3371 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 
| 3297 #undef DEFINE_BUILTIN_ACCESSOR_C | 3372 #undef DEFINE_BUILTIN_ACCESSOR_C | 
| 3298 #undef DEFINE_BUILTIN_ACCESSOR_A | 3373 #undef DEFINE_BUILTIN_ACCESSOR_A | 
| 3299 | 3374 | 
| 3300 | 3375 | 
| 3301 } // namespace internal | 3376 } // namespace internal | 
| 3302 } // namespace v8 | 3377 } // namespace v8 | 
| OLD | NEW |