| 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 |