OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <sstream> | 9 #include <sstream> |
10 | 10 |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "src/debug/debug.h" | 23 #include "src/debug/debug.h" |
24 #include "src/deoptimizer.h" | 24 #include "src/deoptimizer.h" |
25 #include "src/elements.h" | 25 #include "src/elements.h" |
26 #include "src/execution.h" | 26 #include "src/execution.h" |
27 #include "src/field-index.h" | 27 #include "src/field-index.h" |
28 #include "src/field-index-inl.h" | 28 #include "src/field-index-inl.h" |
29 #include "src/full-codegen/full-codegen.h" | 29 #include "src/full-codegen/full-codegen.h" |
30 #include "src/ic/ic.h" | 30 #include "src/ic/ic.h" |
31 #include "src/interpreter/bytecodes.h" | 31 #include "src/interpreter/bytecodes.h" |
32 #include "src/isolate-inl.h" | 32 #include "src/isolate-inl.h" |
| 33 #include "src/key-accumulator.h" |
33 #include "src/list.h" | 34 #include "src/list.h" |
34 #include "src/log.h" | 35 #include "src/log.h" |
35 #include "src/lookup.h" | 36 #include "src/lookup.h" |
36 #include "src/macro-assembler.h" | 37 #include "src/macro-assembler.h" |
37 #include "src/messages.h" | 38 #include "src/messages.h" |
38 #include "src/objects-inl.h" | 39 #include "src/objects-inl.h" |
39 #include "src/profiler/cpu-profiler.h" | 40 #include "src/profiler/cpu-profiler.h" |
40 #include "src/property-descriptor.h" | 41 #include "src/property-descriptor.h" |
41 #include "src/prototype.h" | 42 #include "src/prototype.h" |
42 #include "src/safepoint-table.h" | 43 #include "src/safepoint-table.h" |
(...skipping 7496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7539 if (length == 0) { | 7540 if (length == 0) { |
7540 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); | 7541 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
7541 } | 7542 } |
7542 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); | 7543 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
7543 dictionary->CopyEnumKeysTo(*storage); | 7544 dictionary->CopyEnumKeysTo(*storage); |
7544 return storage; | 7545 return storage; |
7545 } | 7546 } |
7546 } | 7547 } |
7547 | 7548 |
7548 | 7549 |
7549 KeyAccumulator::~KeyAccumulator() { | |
7550 for (size_t i = 0; i < elements_.size(); i++) { | |
7551 delete elements_[i]; | |
7552 } | |
7553 } | |
7554 | |
7555 | |
7556 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { | |
7557 if (length_ == 0) { | |
7558 return isolate_->factory()->empty_fixed_array(); | |
7559 } | |
7560 // Make sure we have all the lengths collected. | |
7561 NextPrototype(); | |
7562 | |
7563 // Assemble the result array by first adding the element keys and then | |
7564 // the property keys. We use the total number of keys per level in | |
7565 // |protoLengths_| and the available element keys in the corresponding bucket | |
7566 // in |elements_| to deduce the number of keys to take from the |properties_| | |
7567 // set. | |
7568 Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_); | |
7569 int index = 0; | |
7570 int properties_index = 0; | |
7571 for (size_t level = 0; level < levelLengths_.size(); level++) { | |
7572 int num_total = levelLengths_[level]; | |
7573 int num_elements = 0; | |
7574 if (num_total < 0) { | |
7575 // If the total is negative, the current level contains properties from a | |
7576 // proxy, hence we skip the integer keys in |elements_| since proxies | |
7577 // define the complete ordering. | |
7578 num_total = -num_total; | |
7579 } else if (level < elements_.size()) { | |
7580 std::vector<uint32_t>* elements = elements_[level]; | |
7581 num_elements = static_cast<int>(elements->size()); | |
7582 for (int i = 0; i < num_elements; i++) { | |
7583 Handle<Object> key; | |
7584 if (convert == KEEP_NUMBERS) { | |
7585 key = isolate_->factory()->NewNumberFromUint(elements->at(i)); | |
7586 } else { | |
7587 key = isolate_->factory()->Uint32ToString(elements->at(i)); | |
7588 } | |
7589 result->set(index, *key); | |
7590 index++; | |
7591 } | |
7592 } | |
7593 // Add the property keys for this prototype level. | |
7594 int num_properties = num_total - num_elements; | |
7595 for (int i = 0; i < num_properties; i++) { | |
7596 Object* key = properties_->KeyAt(properties_index); | |
7597 result->set(index, key); | |
7598 index++; | |
7599 properties_index++; | |
7600 } | |
7601 } | |
7602 | |
7603 DCHECK_EQ(index, length_); | |
7604 return result; | |
7605 } | |
7606 | |
7607 | |
7608 namespace { | |
7609 | |
7610 bool AccumulatorHasKey(std::vector<uint32_t>* sub_elements, uint32_t key) { | |
7611 return std::binary_search(sub_elements->begin(), sub_elements->end(), key); | |
7612 } | |
7613 | |
7614 } // namespace | |
7615 | |
7616 | |
7617 bool KeyAccumulator::AddKey(uint32_t key) { | |
7618 // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). | |
7619 // We mark proxy-levels with a negative length | |
7620 DCHECK_LE(0, levelLength_); | |
7621 // Binary search over all but the last level. The last one might not be | |
7622 // sorted yet. | |
7623 for (size_t i = 1; i < elements_.size(); i++) { | |
7624 if (AccumulatorHasKey(elements_[i - 1], key)) return false; | |
7625 } | |
7626 elements_.back()->push_back(key); | |
7627 length_++; | |
7628 levelLength_++; | |
7629 return true; | |
7630 } | |
7631 | |
7632 | |
7633 bool KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { | |
7634 return AddKey(handle(key, isolate_), convert); | |
7635 } | |
7636 | |
7637 | |
7638 bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { | |
7639 if (filter_ == SKIP_SYMBOLS && key->IsSymbol()) { | |
7640 return false; | |
7641 } | |
7642 // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). | |
7643 DCHECK_LE(0, levelLength_); | |
7644 // In some cases (e.g. proxies) we might get in String-converted ints which | |
7645 // should be added to the elements list instead of the properties. For | |
7646 // proxies we have to convert as well but also respect the original order. | |
7647 // Therefore we add a converted key to both sides | |
7648 if (convert == CONVERT_TO_ARRAY_INDEX || convert == PROXY_MAGIC) { | |
7649 uint32_t index = 0; | |
7650 int prev_length = length_; | |
7651 int prev_proto = levelLength_; | |
7652 bool was_array_index = false; | |
7653 bool key_was_added = false; | |
7654 if ((key->IsString() && Handle<String>::cast(key)->AsArrayIndex(&index)) || | |
7655 key->ToArrayIndex(&index)) { | |
7656 key_was_added = AddKey(index); | |
7657 was_array_index = true; | |
7658 if (convert == CONVERT_TO_ARRAY_INDEX) return key_was_added; | |
7659 } | |
7660 if (was_array_index && convert == PROXY_MAGIC) { | |
7661 // If we had an array index (number) and it wasn't added, the key | |
7662 // already existed before, hence we cannot add it to the properties | |
7663 // keys as it would lead to duplicate entries. | |
7664 if (!key_was_added) { | |
7665 return false; | |
7666 } | |
7667 length_ = prev_length; | |
7668 levelLength_ = prev_proto; | |
7669 } | |
7670 } | |
7671 if (properties_.is_null()) { | |
7672 properties_ = OrderedHashSet::Allocate(isolate_, 16); | |
7673 } | |
7674 // TODO(cbruni): remove this conversion once we throw the correct TypeError | |
7675 // for non-string/symbol elements returned by proxies | |
7676 if (convert == PROXY_MAGIC && key->IsNumber()) { | |
7677 key = isolate_->factory()->NumberToString(key); | |
7678 } | |
7679 int prev_size = properties_->NumberOfElements(); | |
7680 properties_ = OrderedHashSet::Add(properties_, key); | |
7681 if (prev_size < properties_->NumberOfElements()) { | |
7682 length_++; | |
7683 levelLength_++; | |
7684 } | |
7685 return true; | |
7686 } | |
7687 | |
7688 | |
7689 void KeyAccumulator::AddKeys(Handle<FixedArray> array, | |
7690 AddKeyConversion convert) { | |
7691 int add_length = array->length(); | |
7692 if (add_length == 0) return; | |
7693 for (int i = 0; i < add_length; i++) { | |
7694 Handle<Object> current(array->get(i), isolate_); | |
7695 AddKey(current); | |
7696 } | |
7697 } | |
7698 | |
7699 | |
7700 void KeyAccumulator::AddKeys(Handle<JSObject> array_like, | |
7701 AddKeyConversion convert) { | |
7702 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements()); | |
7703 ElementsAccessor* accessor = array_like->GetElementsAccessor(); | |
7704 accessor->AddElementsToKeyAccumulator(array_like, this, convert); | |
7705 } | |
7706 | |
7707 | |
7708 void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) { | |
7709 // Proxies define a complete list of keys with no distinction of | |
7710 // elements and properties, which breaks the normal assumption for the | |
7711 // KeyAccumulator. | |
7712 AddKeys(array_like, PROXY_MAGIC); | |
7713 // Invert the current length to indicate a present proxy, so we can ignore | |
7714 // element keys for this level. Otherwise we would not fully respect the order | |
7715 // given by the proxy. | |
7716 levelLength_ = -levelLength_; | |
7717 } | |
7718 | |
7719 | |
7720 void KeyAccumulator::AddElementKeysFromInterceptor( | |
7721 Handle<JSObject> array_like) { | |
7722 AddKeys(array_like, CONVERT_TO_ARRAY_INDEX); | |
7723 // The interceptor might introduce duplicates for the current level, since | |
7724 // these keys get added after the objects's normal element keys. | |
7725 SortCurrentElementsListRemoveDuplicates(); | |
7726 } | |
7727 | |
7728 | |
7729 void KeyAccumulator::SortCurrentElementsListRemoveDuplicates() { | |
7730 // Sort and remove duplciated from the current elements level and adjust | |
7731 // the lengths accordingly. | |
7732 auto last_level = elements_.back(); | |
7733 size_t nof_removed_keys = last_level->size(); | |
7734 std::sort(last_level->begin(), last_level->end()); | |
7735 last_level->erase(std::unique(last_level->begin(), last_level->end()), | |
7736 last_level->end()); | |
7737 // Adjust total length / level length by the number of removed duplicates | |
7738 nof_removed_keys -= last_level->size(); | |
7739 levelLength_ -= static_cast<int>(nof_removed_keys); | |
7740 length_ -= static_cast<int>(nof_removed_keys); | |
7741 } | |
7742 | |
7743 | |
7744 void KeyAccumulator::SortCurrentElementsList() { | |
7745 if (elements_.empty()) return; | |
7746 auto element_keys = elements_.back(); | |
7747 std::sort(element_keys->begin(), element_keys->end()); | |
7748 } | |
7749 | |
7750 | |
7751 void KeyAccumulator::NextPrototype() { | |
7752 // Store the protoLength on the first call of this method. | |
7753 if (!elements_.empty()) { | |
7754 levelLengths_.push_back(levelLength_); | |
7755 } | |
7756 elements_.push_back(new std::vector<uint32_t>()); | |
7757 levelLength_ = 0; | |
7758 } | |
7759 | |
7760 | |
7761 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, | 7550 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
7762 KeyCollectionType type, | 7551 KeyCollectionType type, |
7763 KeyFilter filter, | 7552 KeyFilter filter, |
7764 GetKeysConversion getConversion) { | 7553 GetKeysConversion getConversion) { |
7765 USE(ContainsOnlyValidKeys); | 7554 USE(ContainsOnlyValidKeys); |
7766 Isolate* isolate = object->GetIsolate(); | 7555 Isolate* isolate = object->GetIsolate(); |
7767 KeyAccumulator accumulator(isolate, filter); | 7556 KeyAccumulator accumulator(isolate, filter); |
7768 Handle<JSFunction> arguments_function( | 7557 Handle<JSFunction> arguments_function( |
7769 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); | 7558 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); |
7770 PrototypeIterator::WhereToEnd end = type == OWN_ONLY | 7559 PrototypeIterator::WhereToEnd end = type == OWN_ONLY |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7833 !current->HasNamedInterceptor() && | 7622 !current->HasNamedInterceptor() && |
7834 !current->HasIndexedInterceptor()); | 7623 !current->HasIndexedInterceptor()); |
7835 // Compute the property keys and cache them if possible. | 7624 // Compute the property keys and cache them if possible. |
7836 Handle<FixedArray> enum_keys = | 7625 Handle<FixedArray> enum_keys = |
7837 JSObject::GetEnumPropertyKeys(current, cache_enum_length); | 7626 JSObject::GetEnumPropertyKeys(current, cache_enum_length); |
7838 accumulator.AddKeys(enum_keys); | 7627 accumulator.AddKeys(enum_keys); |
7839 } else { | 7628 } else { |
7840 DCHECK(filter == INCLUDE_SYMBOLS); | 7629 DCHECK(filter == INCLUDE_SYMBOLS); |
7841 PropertyAttributes attr_filter = | 7630 PropertyAttributes attr_filter = |
7842 static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL); | 7631 static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL); |
7843 Handle<FixedArray> property_keys = isolate->factory()->NewFixedArray( | 7632 current->CollectOwnPropertyNames(&accumulator, attr_filter); |
7844 current->NumberOfOwnProperties(attr_filter)); | |
7845 current->GetOwnPropertyNames(*property_keys, 0, attr_filter); | |
7846 accumulator.AddKeys(property_keys); | |
7847 } | 7633 } |
7848 | 7634 |
7849 // Add the property keys from the interceptor. | 7635 // Add the property keys from the interceptor. |
7850 if (current->HasNamedInterceptor()) { | 7636 if (current->HasNamedInterceptor()) { |
7851 Handle<JSObject> result; | 7637 Handle<JSObject> result; |
7852 if (JSObject::GetKeysForNamedInterceptor(current, object) | 7638 if (JSObject::GetKeysForNamedInterceptor(current, object) |
7853 .ToHandle(&result)) { | 7639 .ToHandle(&result)) { |
7854 accumulator.AddKeys(result); | 7640 accumulator.AddKeys(result); |
7855 } | 7641 } |
7856 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); | 7642 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); |
(...skipping 7156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15013 } else if (IsJSGlobalObject()) { | 14799 } else if (IsJSGlobalObject()) { |
15014 return global_dictionary()->CopyKeysTo(storage, index, filter, | 14800 return global_dictionary()->CopyKeysTo(storage, index, filter, |
15015 GlobalDictionary::UNSORTED); | 14801 GlobalDictionary::UNSORTED); |
15016 } else { | 14802 } else { |
15017 return property_dictionary()->CopyKeysTo(storage, index, filter, | 14803 return property_dictionary()->CopyKeysTo(storage, index, filter, |
15018 NameDictionary::UNSORTED); | 14804 NameDictionary::UNSORTED); |
15019 } | 14805 } |
15020 } | 14806 } |
15021 | 14807 |
15022 | 14808 |
| 14809 int JSObject::CollectOwnPropertyNames(KeyAccumulator* keys, |
| 14810 PropertyAttributes filter) { |
| 14811 if (HasFastProperties()) { |
| 14812 int nof_keys = keys->length(); |
| 14813 int real_size = map()->NumberOfOwnDescriptors(); |
| 14814 Handle<DescriptorArray> descs(map()->instance_descriptors()); |
| 14815 for (int i = 0; i < real_size; i++) { |
| 14816 if ((descs->GetDetails(i).attributes() & filter) != 0) continue; |
| 14817 Name* key = descs->GetKey(i); |
| 14818 if (key->FilterKey(filter)) continue; |
| 14819 keys->AddKey(key); |
| 14820 } |
| 14821 return nof_keys - keys->length(); |
| 14822 } else if (IsJSGlobalObject()) { |
| 14823 return global_dictionary()->CollectKeysTo(keys, filter); |
| 14824 } else { |
| 14825 return property_dictionary()->CollectKeysTo(keys, filter); |
| 14826 } |
| 14827 } |
| 14828 |
| 14829 |
15023 int JSObject::NumberOfOwnElements(PropertyAttributes filter) { | 14830 int JSObject::NumberOfOwnElements(PropertyAttributes filter) { |
15024 // Fast case for objects with no elements. | 14831 // Fast case for objects with no elements. |
15025 if (!IsJSValue() && HasFastElements()) { | 14832 if (!IsJSValue() && HasFastElements()) { |
15026 uint32_t length = | 14833 uint32_t length = |
15027 IsJSArray() | 14834 IsJSArray() |
15028 ? static_cast<uint32_t>( | 14835 ? static_cast<uint32_t>( |
15029 Smi::cast(JSArray::cast(this)->length())->value()) | 14836 Smi::cast(JSArray::cast(this)->length())->value()) |
15030 : static_cast<uint32_t>(FixedArrayBase::cast(elements())->length()); | 14837 : static_cast<uint32_t>(FixedArrayBase::cast(elements())->length()); |
15031 if (length == 0) return 0; | 14838 if (length == 0) return 0; |
15032 } | 14839 } |
(...skipping 1751 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16784 | 16591 |
16785 template <typename Derived, typename Shape, typename Key> | 16592 template <typename Derived, typename Shape, typename Key> |
16786 int Dictionary<Derived, Shape, Key>::CopyKeysTo( | 16593 int Dictionary<Derived, Shape, Key>::CopyKeysTo( |
16787 FixedArray* storage, int index, PropertyAttributes filter, | 16594 FixedArray* storage, int index, PropertyAttributes filter, |
16788 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) { | 16595 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) { |
16789 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter)); | 16596 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter)); |
16790 int start_index = index; | 16597 int start_index = index; |
16791 int capacity = this->Capacity(); | 16598 int capacity = this->Capacity(); |
16792 for (int i = 0; i < capacity; i++) { | 16599 for (int i = 0; i < capacity; i++) { |
16793 Object* k = this->KeyAt(i); | 16600 Object* k = this->KeyAt(i); |
16794 if (this->IsKey(k) && !k->FilterKey(filter)) { | 16601 if (!this->IsKey(k) || k->FilterKey(filter)) continue; |
16795 if (this->IsDeleted(i)) continue; | 16602 if (this->IsDeleted(i)) continue; |
16796 PropertyDetails details = this->DetailsAt(i); | 16603 PropertyDetails details = this->DetailsAt(i); |
16797 PropertyAttributes attr = details.attributes(); | 16604 PropertyAttributes attr = details.attributes(); |
16798 if ((attr & filter) == 0) storage->set(index++, k); | 16605 if ((attr & filter) != 0) continue; |
16799 } | 16606 storage->set(index++, k); |
16800 } | 16607 } |
16801 if (sort_mode == Dictionary::SORTED) { | 16608 if (sort_mode == Dictionary::SORTED) { |
16802 storage->SortPairs(storage, index); | 16609 storage->SortPairs(storage, index); |
16803 } | 16610 } |
16804 DCHECK(storage->length() >= index); | 16611 DCHECK(storage->length() >= index); |
16805 return index - start_index; | 16612 return index - start_index; |
16806 } | 16613 } |
16807 | 16614 |
16808 | 16615 |
| 16616 template <typename Derived, typename Shape, typename Key> |
| 16617 int Dictionary<Derived, Shape, Key>::CollectKeysTo(KeyAccumulator* keys, |
| 16618 PropertyAttributes filter) { |
| 16619 int capacity = this->Capacity(); |
| 16620 int keyLength = keys->length(); |
| 16621 for (int i = 0; i < capacity; i++) { |
| 16622 Object* k = this->KeyAt(i); |
| 16623 if (!this->IsKey(k) || k->FilterKey(filter)) continue; |
| 16624 if (this->IsDeleted(i)) continue; |
| 16625 PropertyDetails details = this->DetailsAt(i); |
| 16626 PropertyAttributes attr = details.attributes(); |
| 16627 if ((attr & filter) != 0) continue; |
| 16628 keys->AddKey(k); |
| 16629 } |
| 16630 return keyLength - keys->length(); |
| 16631 } |
| 16632 |
| 16633 |
16809 // Backwards lookup (slow). | 16634 // Backwards lookup (slow). |
16810 template<typename Derived, typename Shape, typename Key> | 16635 template<typename Derived, typename Shape, typename Key> |
16811 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) { | 16636 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) { |
16812 int capacity = this->Capacity(); | 16637 int capacity = this->Capacity(); |
16813 for (int i = 0; i < capacity; i++) { | 16638 for (int i = 0; i < capacity; i++) { |
16814 Object* k = this->KeyAt(i); | 16639 Object* k = this->KeyAt(i); |
16815 if (this->IsKey(k)) { | 16640 if (this->IsKey(k)) { |
16816 Object* e = this->ValueAt(i); | 16641 Object* e = this->ValueAt(i); |
16817 // TODO(dcarney): this should be templatized. | 16642 // TODO(dcarney): this should be templatized. |
16818 if (e->IsPropertyCell()) { | 16643 if (e->IsPropertyCell()) { |
(...skipping 1190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18009 if (cell->value() != *new_value) { | 17834 if (cell->value() != *new_value) { |
18010 cell->set_value(*new_value); | 17835 cell->set_value(*new_value); |
18011 Isolate* isolate = cell->GetIsolate(); | 17836 Isolate* isolate = cell->GetIsolate(); |
18012 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 17837 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
18013 isolate, DependentCode::kPropertyCellChangedGroup); | 17838 isolate, DependentCode::kPropertyCellChangedGroup); |
18014 } | 17839 } |
18015 } | 17840 } |
18016 | 17841 |
18017 } // namespace internal | 17842 } // namespace internal |
18018 } // namespace v8 | 17843 } // namespace v8 |
OLD | NEW |