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 7507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7518 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); | 7518 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
7519 } | 7519 } |
7520 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); | 7520 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
7521 dictionary->CopyEnumKeysTo(*storage); | 7521 dictionary->CopyEnumKeysTo(*storage); |
7522 return storage; | 7522 return storage; |
7523 } | 7523 } |
7524 } | 7524 } |
7525 | 7525 |
7526 | 7526 |
7527 KeyAccumulator::~KeyAccumulator() { | 7527 KeyAccumulator::~KeyAccumulator() { |
7528 for (int i = 0; i < elements_.length(); i++) { | 7528 for (size_t i = 0; i < elements_.size(); i++) { |
7529 delete elements_[i]; | 7529 delete elements_[i]; |
7530 } | 7530 } |
7531 } | 7531 } |
7532 | 7532 |
7533 | 7533 |
7534 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { | 7534 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { |
7535 if (length_ == 0) { | 7535 if (length_ == 0) { |
7536 return isolate_->factory()->empty_fixed_array(); | 7536 return isolate_->factory()->empty_fixed_array(); |
7537 } | 7537 } |
7538 // Make sure we have all the lengths collected. | 7538 // Make sure we have all the lengths collected. |
7539 NextPrototype(); | 7539 NextPrototype(); |
7540 | 7540 |
7541 // Assemble the result array by first adding the element keys and then | 7541 // Assemble the result array by first adding the element keys and then |
7542 // the property keys. We use the total number of keys per level in | 7542 // the property keys. We use the total number of keys per level in |
7543 // |protoLengths_| and the available element keys in the corresponding bucket | 7543 // |protoLengths_| and the available element keys in the corresponding bucket |
7544 // in |elements_| to deduce the number of keys to take from the |properties_| | 7544 // in |elements_| to deduce the number of keys to take from the |properties_| |
7545 // set. | 7545 // set. |
7546 Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_); | 7546 Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_); |
7547 int index = 0; | 7547 int index = 0; |
7548 int properties_index = 0; | 7548 int properties_index = 0; |
7549 for (int level = 0; level < levelLengths_.length(); level++) { | 7549 for (size_t level = 0; level < levelLengths_.size(); level++) { |
7550 int num_total = levelLengths_[level]; | 7550 int num_total = levelLengths_[level]; |
7551 int num_elements = 0; | 7551 int num_elements = 0; |
7552 if (num_total < 0) { | 7552 if (num_total < 0) { |
7553 // If the total is negative, the current level contains properties from a | 7553 // If the total is negative, the current level contains properties from a |
7554 // proxy, hence we skip the integer keys in |elements_| since proxies | 7554 // proxy, hence we skip the integer keys in |elements_| since proxies |
7555 // define the complete ordering. | 7555 // define the complete ordering. |
7556 num_total = -num_total; | 7556 num_total = -num_total; |
7557 } else if (level < elements_.length()) { | 7557 } else if (level < elements_.size()) { |
7558 List<uint32_t>* elements = elements_[level]; | 7558 std::vector<uint32_t>* elements = elements_[level]; |
7559 num_elements = elements->length(); | 7559 num_elements = static_cast<int>(elements->size()); |
7560 for (int i = 0; i < num_elements; i++) { | 7560 for (int i = 0; i < num_elements; i++) { |
7561 Handle<Object> key; | 7561 Handle<Object> key; |
7562 if (convert == KEEP_NUMBERS) { | 7562 if (convert == KEEP_NUMBERS) { |
7563 key = isolate_->factory()->NewNumberFromUint(elements->at(i)); | 7563 key = isolate_->factory()->NewNumberFromUint(elements->at(i)); |
7564 } else { | 7564 } else { |
7565 key = isolate_->factory()->Uint32ToString(elements->at(i)); | 7565 key = isolate_->factory()->Uint32ToString(elements->at(i)); |
7566 } | 7566 } |
7567 result->set(index, *key); | 7567 result->set(index, *key); |
7568 index++; | 7568 index++; |
7569 } | 7569 } |
7570 } | 7570 } |
7571 // Add the property keys for this prototype level. | 7571 // Add the property keys for this prototype level. |
7572 int num_properties = num_total - num_elements; | 7572 int num_properties = num_total - num_elements; |
7573 for (int i = 0; i < num_properties; i++) { | 7573 for (int i = 0; i < num_properties; i++) { |
7574 Object* key = properties_->KeyAt(properties_index); | 7574 Object* key = properties_->KeyAt(properties_index); |
7575 result->set(index, key); | 7575 result->set(index, key); |
7576 index++; | 7576 index++; |
7577 properties_index++; | 7577 properties_index++; |
7578 } | 7578 } |
7579 } | 7579 } |
| 7580 |
7580 DCHECK_EQ(index, length_); | 7581 DCHECK_EQ(index, length_); |
7581 return result; | 7582 return result; |
7582 } | 7583 } |
7583 | 7584 |
7584 | 7585 |
7585 namespace { | 7586 namespace { |
7586 | 7587 |
7587 class FindKey { | 7588 bool AccumulatorHasKey(std::vector<uint32_t>* sub_elements, uint32_t key) { |
7588 public: | 7589 return std::binary_search(sub_elements->begin(), sub_elements->end(), key); |
7589 explicit FindKey(uint32_t key) : key_(key) {} | |
7590 int operator()(uint32_t* entry) { | |
7591 if (*entry == key_) return 0; | |
7592 return *entry < key_ ? -1 : 1; | |
7593 } | |
7594 | |
7595 private: | |
7596 uint32_t key_; | |
7597 }; | |
7598 | |
7599 | |
7600 bool AccumulatorHasKey(List<uint32_t>* sub_elements, uint32_t key) { | |
7601 int index = SortedListBSearch(*sub_elements, FindKey(key)); | |
7602 return index != -1; | |
7603 } | 7590 } |
7604 | 7591 |
7605 } // namespace | 7592 } // namespace |
7606 | 7593 |
7607 | 7594 |
7608 bool KeyAccumulator::AddKey(uint32_t key) { | 7595 bool KeyAccumulator::AddKey(uint32_t key) { |
7609 // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). | 7596 // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). |
| 7597 // We mark proxy-levels with a negative length |
7610 DCHECK_LE(0, levelLength_); | 7598 DCHECK_LE(0, levelLength_); |
7611 int lookup_limit = elements_.length(); | 7599 // Binary search over all but the last level. The last one might not be |
7612 for (int i = 0; i < lookup_limit; i++) { | 7600 // sorted yet. |
7613 if (AccumulatorHasKey(elements_[i], key)) return false; | 7601 for (size_t i = 1; i < elements_.size(); i++) { |
| 7602 if (AccumulatorHasKey(elements_[i - 1], key)) return false; |
7614 } | 7603 } |
7615 elements_[lookup_limit - 1]->Add(key); | 7604 elements_.back()->push_back(key); |
7616 length_++; | 7605 length_++; |
7617 levelLength_++; | 7606 levelLength_++; |
7618 return true; | 7607 return true; |
7619 } | 7608 } |
7620 | 7609 |
7621 | 7610 |
7622 bool KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { | 7611 bool KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { |
7623 return AddKey(handle(key, isolate_), convert); | 7612 return AddKey(handle(key, isolate_), convert); |
7624 } | 7613 } |
7625 | 7614 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7699 // elements and properties, which breaks the normal assumption for the | 7688 // elements and properties, which breaks the normal assumption for the |
7700 // KeyAccumulator. | 7689 // KeyAccumulator. |
7701 AddKeys(array_like, PROXY_MAGIC); | 7690 AddKeys(array_like, PROXY_MAGIC); |
7702 // Invert the current length to indicate a present proxy, so we can ignore | 7691 // Invert the current length to indicate a present proxy, so we can ignore |
7703 // element keys for this level. Otherwise we would not fully respect the order | 7692 // element keys for this level. Otherwise we would not fully respect the order |
7704 // given by the proxy. | 7693 // given by the proxy. |
7705 levelLength_ = -levelLength_; | 7694 levelLength_ = -levelLength_; |
7706 } | 7695 } |
7707 | 7696 |
7708 | 7697 |
7709 namespace { | 7698 void KeyAccumulator::AddElementKeysFromInterceptor( |
7710 | 7699 Handle<JSObject> array_like) { |
7711 // Used for sorting indices in a List<uint32_t>. | 7700 AddKeys(array_like, CONVERT_TO_ARRAY_INDEX); |
7712 int compareUInt32(const uint32_t* ap, const uint32_t* bp) { | 7701 SortRemoveDuplicates(); |
7713 uint32_t a = *ap; | |
7714 uint32_t b = *bp; | |
7715 return (a == b) ? 0 : (a < b) ? -1 : 1; | |
7716 } | 7702 } |
7717 | 7703 |
7718 | 7704 |
7719 } // namespace | 7705 void KeyAccumulator::SortRemoveDuplicates() { |
| 7706 // The accumulator might introduce duplicates for the current level, since |
| 7707 // these keys get added after the object's element keys. |
| 7708 auto last_level = elements_.back(); |
| 7709 size_t nof_removed_keys = last_level->size(); |
| 7710 std::sort(last_level->begin(), last_level->end()); |
| 7711 last_level->erase(std::unique(last_level->begin(), last_level->end()), |
| 7712 last_level->end()); |
| 7713 // Adjust total length / level length by the number of removed duplicates |
| 7714 nof_removed_keys -= last_level->size(); |
| 7715 levelLength_ -= static_cast<int>(nof_removed_keys); |
| 7716 length_ -= static_cast<int>(nof_removed_keys); |
| 7717 } |
7720 | 7718 |
7721 | 7719 |
7722 void KeyAccumulator::SortCurrentElementsList() { | 7720 void KeyAccumulator::SortCurrentElementsList() { |
7723 if (elements_.length() == 0) return; | 7721 if (elements_.empty()) return; |
7724 List<uint32_t>* element_keys = elements_[elements_.length() - 1]; | 7722 auto element_keys = elements_.back(); |
7725 element_keys->Sort(&compareUInt32); | 7723 std::sort(element_keys->begin(), element_keys->end()); |
7726 } | 7724 } |
7727 | 7725 |
7728 | 7726 |
7729 void KeyAccumulator::NextPrototype() { | 7727 void KeyAccumulator::NextPrototype() { |
7730 // Store the protoLength on the first call of this method. | 7728 // Store the protoLength on the first call of this method. |
7731 if (!elements_.is_empty()) { | 7729 if (!elements_.empty()) { |
7732 levelLengths_.Add(levelLength_); | 7730 levelLengths_.push_back(levelLength_); |
7733 } | 7731 } |
7734 elements_.Add(new List<uint32_t>()); | 7732 elements_.push_back(new std::vector<uint32_t>()); |
7735 levelLength_ = 0; | 7733 levelLength_ = 0; |
7736 } | 7734 } |
7737 | 7735 |
7738 | 7736 |
7739 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, | 7737 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
7740 KeyCollectionType type, | 7738 KeyCollectionType type, |
7741 KeyFilter filter, | 7739 KeyFilter filter, |
7742 GetKeysConversion getConversion) { | 7740 GetKeysConversion getConversion) { |
7743 USE(ContainsOnlyValidKeys); | 7741 USE(ContainsOnlyValidKeys); |
7744 Isolate* isolate = object->GetIsolate(); | 7742 Isolate* isolate = object->GetIsolate(); |
7745 KeyAccumulator accumulator(isolate, filter); | 7743 KeyAccumulator accumulator(isolate, filter); |
7746 Handle<JSFunction> arguments_function( | 7744 Handle<JSFunction> arguments_function( |
7747 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); | 7745 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); |
7748 | |
7749 PrototypeIterator::WhereToEnd end = type == OWN_ONLY | 7746 PrototypeIterator::WhereToEnd end = type == OWN_ONLY |
7750 ? PrototypeIterator::END_AT_NON_HIDDEN | 7747 ? PrototypeIterator::END_AT_NON_HIDDEN |
7751 : PrototypeIterator::END_AT_NULL; | 7748 : PrototypeIterator::END_AT_NULL; |
7752 // Only collect keys if access is permitted. | 7749 // Only collect keys if access is permitted. |
7753 for (PrototypeIterator iter(isolate, object, | 7750 for (PrototypeIterator iter(isolate, object, |
7754 PrototypeIterator::START_AT_RECEIVER); | 7751 PrototypeIterator::START_AT_RECEIVER); |
7755 !iter.IsAtEnd(end); iter.Advance()) { | 7752 !iter.IsAtEnd(end); iter.Advance()) { |
7756 accumulator.NextPrototype(); | 7753 accumulator.NextPrototype(); |
7757 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | 7754 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
7758 Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter); | 7755 Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter); |
(...skipping 24 matching lines...) Expand all Loading... |
7783 } | 7780 } |
7784 | 7781 |
7785 JSObject::CollectOwnElementKeys(current, &accumulator, | 7782 JSObject::CollectOwnElementKeys(current, &accumulator, |
7786 static_cast<PropertyAttributes>(DONT_ENUM)); | 7783 static_cast<PropertyAttributes>(DONT_ENUM)); |
7787 | 7784 |
7788 // Add the element keys from the interceptor. | 7785 // Add the element keys from the interceptor. |
7789 if (current->HasIndexedInterceptor()) { | 7786 if (current->HasIndexedInterceptor()) { |
7790 Handle<JSObject> result; | 7787 Handle<JSObject> result; |
7791 if (JSObject::GetKeysForIndexedInterceptor(current, object) | 7788 if (JSObject::GetKeysForIndexedInterceptor(current, object) |
7792 .ToHandle(&result)) { | 7789 .ToHandle(&result)) { |
7793 accumulator.AddKeys(result, CONVERT_TO_ARRAY_INDEX); | 7790 accumulator.AddElementKeysFromInterceptor(result); |
7794 } | 7791 } |
7795 } | 7792 } |
7796 | 7793 |
7797 if (filter == SKIP_SYMBOLS) { | 7794 if (filter == SKIP_SYMBOLS) { |
7798 // We can cache the computed property keys if access checks are | 7795 // We can cache the computed property keys if access checks are |
7799 // not needed and no interceptors are involved. | 7796 // not needed and no interceptors are involved. |
7800 // | 7797 // |
7801 // We do not use the cache if the object has elements and | 7798 // We do not use the cache if the object has elements and |
7802 // therefore it does not make sense to cache the property names | 7799 // therefore it does not make sense to cache the property names |
7803 // for arguments objects. Arguments objects will always have | 7800 // for arguments objects. Arguments objects will always have |
(...skipping 10043 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17847 if (cell->value() != *new_value) { | 17844 if (cell->value() != *new_value) { |
17848 cell->set_value(*new_value); | 17845 cell->set_value(*new_value); |
17849 Isolate* isolate = cell->GetIsolate(); | 17846 Isolate* isolate = cell->GetIsolate(); |
17850 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 17847 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
17851 isolate, DependentCode::kPropertyCellChangedGroup); | 17848 isolate, DependentCode::kPropertyCellChangedGroup); |
17852 } | 17849 } |
17853 } | 17850 } |
17854 | 17851 |
17855 } // namespace internal | 17852 } // namespace internal |
17856 } // namespace v8 | 17853 } // namespace v8 |
OLD | NEW |