Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: src/objects.cc

Issue 1425403002: [runtime] Support Symbols in KeyAccumulator (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: updating + clarifying Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/objects.h ('k') | src/runtime/runtime-array.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/runtime/runtime-array.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698