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

Side by Side Diff: src/objects.cc

Issue 1397063002: [runtime] Fancify KeyAccumulator (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: documentation + cleanup Created 5 years, 2 months 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
11 #include "src/accessors.h" 11 #include "src/accessors.h"
12 #include "src/allocation-site-scopes.h" 12 #include "src/allocation-site-scopes.h"
13 #include "src/api.h" 13 #include "src/api.h"
14 #include "src/arguments.h" 14 #include "src/arguments.h"
15 #include "src/base/bits.h" 15 #include "src/base/bits.h"
16 #include "src/base/utils/random-number-generator.h" 16 #include "src/base/utils/random-number-generator.h"
17 #include "src/bootstrapper.h" 17 #include "src/bootstrapper.h"
18 #include "src/code-stubs.h" 18 #include "src/code-stubs.h"
19 #include "src/codegen.h" 19 #include "src/codegen.h"
20 #include "src/compilation-dependencies.h" 20 #include "src/compilation-dependencies.h"
21 #include "src/compiler.h" 21 #include "src/compiler.h"
22 #include "src/date.h" 22 #include "src/date.h"
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-inl.h" 28 #include "src/field-index-inl.h"
28 #include "src/field-index.h"
29 #include "src/full-codegen/full-codegen.h" 29 #include "src/full-codegen/full-codegen.h"
30 #include "src/hydrogen.h" 30 #include "src/hydrogen.h"
31 #include "src/ic/ic.h" 31 #include "src/ic/ic.h"
32 #include "src/interpreter/bytecodes.h" 32 #include "src/interpreter/bytecodes.h"
33 #include "src/isolate-inl.h" 33 #include "src/isolate-inl.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/prototype.h" 41 #include "src/prototype.h"
41 #include "src/safepoint-table.h" 42 #include "src/safepoint-table.h"
42 #include "src/string-builder.h" 43 #include "src/string-builder.h"
43 #include "src/string-search.h" 44 #include "src/string-search.h"
(...skipping 6726 matching lines...) Expand 10 before | Expand all | Expand 10 after
6770 if (length == 0) { 6771 if (length == 0) {
6771 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); 6772 return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
6772 } 6773 }
6773 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); 6774 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
6774 dictionary->CopyEnumKeysTo(*storage); 6775 dictionary->CopyEnumKeysTo(*storage);
6775 return storage; 6776 return storage;
6776 } 6777 }
6777 } 6778 }
6778 6779
6779 6780
6780 Handle<FixedArray> KeyAccumulator::GetKeys() { 6781 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
6781 if (length_ == 0) { 6782 if (length_ == 0) {
6782 return isolate_->factory()->empty_fixed_array(); 6783 return isolate_->factory()->empty_fixed_array();
6783 } 6784 }
6784 if (set_.is_null()) { 6785 // make sure we have all the lengths collected
6785 keys_->Shrink(length_); 6786 NextPrototype();
6786 return keys_; 6787
6787 } 6788 // Assemble the result array by first adding the element keys and then
6788 // copy over results from set_ 6789 // the property keys. We use the total number of keys per level in
6790 // |protoLengths_| and the available element keys in the corresponding bucket
6791 // in |elements_| to deduce the number of keys to take from the |properties_|
6792 // set.
6789 Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_); 6793 Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_);
6790 for (int i = 0; i < length_; i++) { 6794 int index = 0;
6791 result->set(i, set_->KeyAt(i)); 6795 int properties_index = 0;
6796 for (int level = 0; level < levelLengths_.length(); level++) {
6797 int num_total = levelLengths_[level];
6798 int num_elements = 0;
6799 if (num_total < 0) {
6800 // If the total is negative, the current level contains properties from a
6801 // proxy, hence we skip the integer keys in |elements_| since procies
6802 // define the complete ordering.
6803 num_total = -num_total;
6804 } else if (level < elements_.length()) {
6805 List<uint32_t>* elements = elements_[level];
6806 num_elements = elements->length();
6807 for (int i = 0; i < num_elements; i++) {
6808 Handle<Object> key;
6809 if (convert == KEEP_NUMBERS) {
6810 key = isolate_->factory()->NewNumberFromUint(elements->at(i));
6811 } else {
6812 key = isolate_->factory()->Uint32ToString(elements->at(i));
6813 }
6814 result->set(index, *key);
6815 index++;
6816 }
6817 }
6818 // Add the property keys for this prototype level.
6819 int num_properties = num_total - num_elements;
6820 for (int i = 0; i < num_properties; i++) {
6821 Object* key = properties_->KeyAt(properties_index);
6822 result->set(index, key);
6823 index++;
6824 properties_index++;
6825 }
6792 } 6826 }
6793 return result; 6827 return result;
6794 } 6828 }
6795 6829
6796 6830
6797 void KeyAccumulator::AddKey(Handle<Object> key, int check_limit) { 6831 namespace {
6798 #ifdef ENABLE_SLOW_DCHECKS 6832
6799 if (FLAG_enable_slow_asserts) { 6833 class FindKey {
6800 DCHECK(key->IsNumber() || key->IsName()); 6834 public:
6801 } 6835 explicit FindKey(uint32_t key) : key_(key) {}
6802 #endif 6836 int operator()(uint32_t* entry) {
6803 if (!set_.is_null()) { 6837 if (*entry == key_) return 0;
6804 set_ = OrderedHashSet::Add(set_, key); 6838 return *entry < key_ ? -1 : 1;
6805 length_ = set_->NumberOfElements(); 6839 }
6806 return; 6840
6807 } 6841 private:
6808 // check if we already have the key in the case we are still using 6842 uint32_t key_;
6809 // the keys_ FixedArray 6843 };
6810 check_limit = Min(check_limit, length_); 6844
6811 for (int i = 0; i < check_limit; i++) { 6845
6812 Object* current = keys_->get(i); 6846 bool AccumulatorHasKey(List<uint32_t>* sub_elements, uint32_t key) {
6813 if (current->KeyEquals(*key)) return; 6847 int index = SortedListBSearch(*sub_elements, FindKey(key));
6814 } 6848 return index != -1;
6815 EnsureCapacity(length_); 6849 }
6816 keys_->set(length_, *key); 6850
6851 } // namespace
6852
6853
6854 bool KeyAccumulator::AddKey(uint32_t key) {
6855 int lookup_limit = elements_.length();
6856 for (int i = 0; i < lookup_limit; i++) {
6857 if (AccumulatorHasKey(elements_[i], key)) return false;
6858 }
6859 elements_[lookup_limit - 1]->Add(key);
6817 length_++; 6860 length_++;
6818 } 6861 levelLength_++;
6819 6862 return true;
6820 6863 }
6821 void KeyAccumulator::AddKeys(Handle<FixedArray> array, KeyFilter filter) { 6864
6865
6866 bool KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) {
6867 return AddKey(handle(key, isolate_), convert);
6868 }
6869
6870
6871 bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
6872 if (filter_ == SKIP_SYMBOLS && key->IsSymbol()) {
6873 return false;
6874 }
6875 // In some cases (e.g. proxies) we might get in String-converted ints which
6876 // should be added to the elements list instead of the properties. For
6877 // proxies we have to convert as well but also respect the original order.
6878 // Therefore we add a converted key to both sides
6879 if (convert == CONVERT_TO_ARRAY_INDEX || convert == PROXY_MAGIC) {
6880 uint32_t index = 0;
6881 int prev_length = length_;
6882 int prev_proto = levelLength_;
6883 bool was_array_index = false;
6884 bool key_was_added = false;
6885 if ((key->IsString() && Handle<String>::cast(key)->AsArrayIndex(&index)) ||
6886 key->ToArrayIndex(&index)) {
6887 key_was_added = AddKey(index);
6888 was_array_index = true;
6889 if (convert == CONVERT_TO_ARRAY_INDEX) return key_was_added;
6890 }
6891 if (was_array_index && convert == PROXY_MAGIC) {
6892 // If we had an array index (number) and it wasn't added, the key
6893 // already existed before, hence we cannot add it to the properties
6894 // keys as it would lead to duplicate entries.
6895 if (!key_was_added) {
6896 return false;
6897 }
6898 length_ = prev_length;
6899 levelLength_ = prev_proto;
6900 }
6901 }
6902 if (properties_.is_null()) {
6903 properties_ = OrderedHashSet::Allocate(isolate_, 16);
6904 }
6905 // TODO(cbruni): remove this conversion once we throw the correct TypeError
6906 // for non-string/symbol elements returned by proxies
6907 if (convert == PROXY_MAGIC && key->IsNumber()) {
6908 key = isolate_->factory()->NumberToString(key);
6909 }
6910 int prev_size = properties_->NumberOfElements();
6911 properties_ = OrderedHashSet::Add(properties_, key);
6912 if (prev_size < properties_->NumberOfElements()) {
6913 length_++;
6914 levelLength_++;
6915 }
6916 return true;
6917 }
6918
6919
6920 void KeyAccumulator::AddKeys(Handle<FixedArray> array,
6921 AddKeyConversion convert) {
6822 int add_length = array->length(); 6922 int add_length = array->length();
6823 if (add_length == 0) return; 6923 if (add_length == 0) return;
6824 if (keys_.is_null() && filter == INCLUDE_SYMBOLS) {
6825 keys_ = array;
6826 length_ = keys_->length();
6827 return;
6828 }
6829 PrepareForComparisons(add_length);
6830 int previous_key_count = length_;
6831 for (int i = 0; i < add_length; i++) { 6924 for (int i = 0; i < add_length; i++) {
6832 Handle<Object> current(array->get(i), isolate_); 6925 Handle<Object> current(array->get(i), isolate_);
6833 if (filter == SKIP_SYMBOLS && current->IsSymbol()) continue; 6926 AddKey(current);
6834 AddKey(current, previous_key_count); 6927 }
6835 } 6928 }
6836 } 6929
6837 6930
6838 6931 void KeyAccumulator::AddKeys(Handle<JSObject> array_like,
6839 void KeyAccumulator::AddKeys(Handle<JSObject> array_like, KeyFilter filter) { 6932 AddKeyConversion convert) {
6840 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements()); 6933 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements());
6841 ElementsAccessor* accessor = array_like->GetElementsAccessor(); 6934 ElementsAccessor* accessor = array_like->GetElementsAccessor();
6842 accessor->AddElementsToKeyAccumulator(array_like, this, filter); 6935 accessor->AddElementsToKeyAccumulator(array_like, this, convert);
6843 } 6936 }
6844 6937
6845 6938
6846 void KeyAccumulator::PrepareForComparisons(int count) { 6939 void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) {
6847 // Depending on how many comparisons we do we should switch to the 6940 // Proxies define a complete list of keys with no distinction of
6848 // hash-table-based checks which have a one-time overhead for 6941 // elements and properties, which breaks the normal assumption for the
6849 // initializing but O(1) for HasKey checks. 6942 // KeyAccumulator.
6850 if (!set_.is_null()) return; 6943 AddKeys(array_like, PROXY_MAGIC);
6851 // These limits were obtained through evaluation of several microbenchmarks. 6944 // Invert the current length to indicate a present proxy, so we can ignore
6852 if (length_ * count < 100) return; 6945 // element keys for this level. Otherwise we would not fully respect the order
6853 // Don't use a set for few elements 6946 // given by the proxy.
6854 if (length_ < 100 && count < 20) return; 6947 levelLength_ = -levelLength_;
6855 set_ = OrderedHashSet::Allocate(isolate_, length_); 6948 }
6856 for (int i = 0; i < length_; i++) { 6949
6857 Handle<Object> value(keys_->get(i), isolate_); 6950
6858 set_ = OrderedHashSet::Add(set_, value); 6951 namespace {
6859 } 6952
6860 } 6953 // Used for sorting indices in a List<uint32_t>.
6861 6954 int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
6862 6955 uint32_t a = *ap;
6863 void KeyAccumulator::EnsureCapacity(int capacity) { 6956 uint32_t b = *bp;
6864 if (keys_.is_null() || keys_->length() <= capacity) { 6957 return (a == b) ? 0 : (a < b) ? -1 : 1;
6865 Grow(); 6958 }
6866 } 6959
6867 } 6960
6868 6961 } // namespace
6869 6962
6870 void KeyAccumulator::Grow() { 6963
6871 // The OrderedHashSet handles growing by itself. 6964 void KeyAccumulator::SortCurrentElementsList() {
6872 if (!set_.is_null()) return; 6965 if (elements_.length() == 0) return;
6873 // Otherwise, grow the internal keys_ FixedArray 6966 List<uint32_t>* element_keys = elements_[elements_.length() - 1];
6874 int capacity = keys_.is_null() ? 16 : keys_->length() * 2 + 16; 6967 element_keys->Sort(&compareUInt32);
6875 Handle<FixedArray> new_keys = isolate_->factory()->NewFixedArray(capacity); 6968 }
6876 if (keys_.is_null()) { 6969
6877 keys_ = new_keys; 6970
6878 return; 6971 void KeyAccumulator::NextPrototype() {
6879 } 6972 // Store the protoLength on the first call of this method.
6880 int buffer_length = keys_->length(); 6973 if (!elements_.is_empty()) {
6881 { 6974 levelLengths_.Add(levelLength_);
6882 DisallowHeapAllocation no_gc; 6975 }
6883 WriteBarrierMode mode = new_keys->GetWriteBarrierMode(no_gc); 6976 elements_.Add(new List<uint32_t>());
Camillo Bruni 2015/10/13 13:49:26 I am not sure how these lists are freed. I presume
6884 for (int i = 0; i < buffer_length; i++) { 6977 levelLength_ = 0;
6885 new_keys->set(i, keys_->get(i), mode); 6978 }
6886 } 6979
6887 } 6980
6888 keys_ = new_keys;
6889 }
6890
6891
6892 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, 6981 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
6893 KeyCollectionType type, 6982 KeyCollectionType type,
6894 KeyFilter filter) { 6983 KeyFilter filter) {
6895 USE(ContainsOnlyValidKeys); 6984 USE(ContainsOnlyValidKeys);
6896 Isolate* isolate = object->GetIsolate(); 6985 Isolate* isolate = object->GetIsolate();
6897 KeyAccumulator accumulator(isolate); 6986 KeyAccumulator accumulator(isolate, filter);
6898 Handle<JSFunction> arguments_function( 6987 Handle<JSFunction> arguments_function(
6899 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); 6988 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
6900 6989
6901 PrototypeIterator::WhereToEnd end = type == OWN_ONLY 6990 PrototypeIterator::WhereToEnd end = type == OWN_ONLY
6902 ? PrototypeIterator::END_AT_NON_HIDDEN 6991 ? PrototypeIterator::END_AT_NON_HIDDEN
6903 : PrototypeIterator::END_AT_NULL; 6992 : PrototypeIterator::END_AT_NULL;
6904 // Only collect keys if access is permitted. 6993 // Only collect keys if access is permitted.
6905 for (PrototypeIterator iter(isolate, object, 6994 for (PrototypeIterator iter(isolate, object,
6906 PrototypeIterator::START_AT_RECEIVER); 6995 PrototypeIterator::START_AT_RECEIVER);
6907 !iter.IsAtEnd(end); iter.Advance()) { 6996 !iter.IsAtEnd(end); iter.Advance()) {
6997 accumulator.NextPrototype();
6908 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { 6998 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
6909 Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter); 6999 Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter);
6910 Handle<Object> args[] = { proxy }; 7000 Handle<Object> args[] = { proxy };
6911 Handle<Object> names; 7001 Handle<Object> names;
6912 ASSIGN_RETURN_ON_EXCEPTION( 7002 ASSIGN_RETURN_ON_EXCEPTION(
6913 isolate, names, 7003 isolate, names,
6914 Execution::Call(isolate, 7004 Execution::Call(isolate,
6915 isolate->proxy_enumerate(), 7005 isolate->proxy_enumerate(),
6916 object, 7006 object,
6917 arraysize(args), 7007 arraysize(args),
6918 args), 7008 args),
6919 FixedArray); 7009 FixedArray);
6920 accumulator.AddKeys(Handle<JSObject>::cast(names), filter); 7010 accumulator.AddKeysFromProxy(Handle<JSObject>::cast(names));
6921 break; 7011 break;
6922 } 7012 }
6923 7013
6924 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); 7014 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
6925 7015
6926 // Check access rights if required. 7016 // Check access rights if required.
6927 if (current->IsAccessCheckNeeded() && 7017 if (current->IsAccessCheckNeeded() &&
6928 !isolate->MayAccess(handle(isolate->context()), current)) { 7018 !isolate->MayAccess(handle(isolate->context()), current)) {
6929 if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { 7019 if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
6930 isolate->ReportFailedAccessCheck(current); 7020 isolate->ReportFailedAccessCheck(current);
6931 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); 7021 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
6932 } 7022 }
6933 break; 7023 break;
6934 } 7024 }
6935 7025
6936 // Compute the element keys. 7026 JSObject::CollectOwnElementKeys(current, &accumulator,
6937 Handle<FixedArray> element_keys = 7027 static_cast<PropertyAttributes>(DONT_ENUM));
6938 isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
6939 current->GetEnumElementKeys(*element_keys);
6940 accumulator.AddKeys(element_keys, filter);
6941 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
6942 7028
6943 // Add the element keys from the interceptor. 7029 // Add the element keys from the interceptor.
6944 if (current->HasIndexedInterceptor()) { 7030 if (current->HasIndexedInterceptor()) {
6945 Handle<JSObject> result; 7031 Handle<JSObject> result;
6946 if (JSObject::GetKeysForIndexedInterceptor( 7032 if (JSObject::GetKeysForIndexedInterceptor(current, object)
6947 current, object).ToHandle(&result)) { 7033 .ToHandle(&result)) {
6948 accumulator.AddKeys(result, filter); 7034 accumulator.AddKeys(result, CONVERT_TO_ARRAY_INDEX);
6949 } 7035 }
6950 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
6951 } 7036 }
6952 7037
6953 if (filter == SKIP_SYMBOLS) { 7038 if (filter == SKIP_SYMBOLS) {
6954 // We can cache the computed property keys if access checks are 7039 // We can cache the computed property keys if access checks are
6955 // not needed and no interceptors are involved. 7040 // not needed and no interceptors are involved.
6956 // 7041 //
6957 // We do not use the cache if the object has elements and 7042 // We do not use the cache if the object has elements and
6958 // therefore it does not make sense to cache the property names 7043 // therefore it does not make sense to cache the property names
6959 // for arguments objects. Arguments objects will always have 7044 // for arguments objects. Arguments objects will always have
6960 // elements. 7045 // elements.
6961 // Wrapped strings have elements, but don't have an elements 7046 // Wrapped strings have elements, but don't have an elements
6962 // array or dictionary. So the fast inline test for whether to 7047 // array or dictionary. So the fast inline test for whether to
6963 // use the cache says yes, so we should not create a cache. 7048 // use the cache says yes, so we should not create a cache.
6964 bool cache_enum_length = 7049 bool cache_enum_length =
6965 ((current->map()->GetConstructor() != *arguments_function) && 7050 ((current->map()->GetConstructor() != *arguments_function) &&
6966 !current->IsJSValue() && !current->IsAccessCheckNeeded() && 7051 !current->IsJSValue() && !current->IsAccessCheckNeeded() &&
6967 !current->HasNamedInterceptor() && 7052 !current->HasNamedInterceptor() &&
6968 !current->HasIndexedInterceptor()); 7053 !current->HasIndexedInterceptor());
6969 // Compute the property keys and cache them if possible. 7054 // Compute the property keys and cache them if possible.
6970 7055
6971 Handle<FixedArray> enum_keys = 7056 Handle<FixedArray> enum_keys =
6972 JSObject::GetEnumPropertyKeys(current, cache_enum_length); 7057 JSObject::GetEnumPropertyKeys(current, cache_enum_length);
6973 accumulator.AddKeys(enum_keys, filter); 7058 accumulator.AddKeys(enum_keys);
6974 } else { 7059 } else {
6975 DCHECK(filter == INCLUDE_SYMBOLS); 7060 DCHECK(filter == INCLUDE_SYMBOLS);
6976 PropertyAttributes attr_filter = 7061 PropertyAttributes attr_filter =
6977 static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL); 7062 static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL);
6978 Handle<FixedArray> property_keys = isolate->factory()->NewFixedArray( 7063 JSObject::CollectOwnElementKeys(current, &accumulator, attr_filter);
6979 current->NumberOfOwnProperties(attr_filter));
6980 current->GetOwnPropertyNames(*property_keys, 0, attr_filter);
6981 accumulator.AddKeys(property_keys, filter);
6982 } 7064 }
6983 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
6984 7065
6985 // Add the property keys from the interceptor. 7066 // Add the property keys from the interceptor.
6986 if (current->HasNamedInterceptor()) { 7067 if (current->HasNamedInterceptor()) {
6987 Handle<JSObject> result; 7068 Handle<JSObject> result;
6988 if (JSObject::GetKeysForNamedInterceptor( 7069 if (JSObject::GetKeysForNamedInterceptor(current, object)
6989 current, object).ToHandle(&result)) { 7070 .ToHandle(&result)) {
6990 accumulator.AddKeys(result, filter); 7071 accumulator.AddKeys(result);
6991 } 7072 }
6992 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
6993 } 7073 }
6994 } 7074 }
6995 7075
6996 Handle<FixedArray> keys = accumulator.GetKeys(); 7076 Handle<FixedArray> keys = accumulator.GetKeys();
6997 DCHECK(ContainsOnlyValidKeys(keys)); 7077 DCHECK(ContainsOnlyValidKeys(keys));
6998 return keys; 7078 return keys;
6999 } 7079 }
7000 7080
7001 7081
7002 bool Map::DictionaryElementsInPrototypeChainOnly() { 7082 bool Map::DictionaryElementsInPrototypeChainOnly() {
(...skipping 6964 matching lines...) Expand 10 before | Expand all | Expand 10 after
13967 // Compute the number of enumerable elements. 14047 // Compute the number of enumerable elements.
13968 return GetOwnElementKeys(NULL, filter); 14048 return GetOwnElementKeys(NULL, filter);
13969 } 14049 }
13970 14050
13971 14051
13972 int JSObject::NumberOfEnumElements() { 14052 int JSObject::NumberOfEnumElements() {
13973 return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM)); 14053 return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM));
13974 } 14054 }
13975 14055
13976 14056
14057 namespace {
14058
14059 void CollectElementIndices(Handle<JSObject> object, uint32_t range,
14060 KeyAccumulator* keys, PropertyAttributes filter,
14061 uint32_t offset) {
14062 ElementsKind kind = object->GetElementsKind();
14063 switch (kind) {
14064 case FAST_SMI_ELEMENTS:
14065 case FAST_ELEMENTS: {
14066 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
14067 uint32_t length = static_cast<uint32_t>(elements->length());
14068 if (range < length) length = range;
14069 for (uint32_t i = offset; i < length; i++) {
14070 keys->AddKey(i);
14071 }
14072 break;
14073 }
14074
14075 case FAST_HOLEY_SMI_ELEMENTS:
14076 case FAST_HOLEY_ELEMENTS: {
14077 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
14078 uint32_t length = static_cast<uint32_t>(elements->length());
14079 if (range < length) length = range;
14080 for (uint32_t i = offset; i < length; i++) {
14081 if (!elements->get(i)->IsTheHole()) {
14082 keys->AddKey(i);
14083 }
14084 }
14085 break;
14086 }
14087 case FAST_HOLEY_DOUBLE_ELEMENTS:
14088 case FAST_DOUBLE_ELEMENTS: {
14089 if (object->elements()->IsFixedArray()) {
14090 DCHECK(object->elements()->length() == 0);
14091 return;
14092 }
14093 Handle<FixedDoubleArray> elements(
14094 FixedDoubleArray::cast(object->elements()));
14095 uint32_t length = static_cast<uint32_t>(elements->length());
14096 if (range < length) length = range;
14097 for (uint32_t i = offset; i < length; i++) {
14098 if (!elements->is_the_hole(i)) {
14099 keys->AddKey(i);
14100 }
14101 }
14102 break;
14103 }
14104 case DICTIONARY_ELEMENTS: {
14105 Handle<SeededNumberDictionary> dict(object->element_dictionary());
14106 SeededNumberDictionary::CopyElementKeysTo(dict, keys, filter, offset);
14107 keys->SortCurrentElementsList();
14108 break;
14109 }
14110 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
14111
14112 TYPED_ARRAYS(TYPED_ARRAY_CASE)
14113 #undef TYPED_ARRAY_CASE
14114 {
14115 uint32_t length = static_cast<uint32_t>(
14116 FixedArrayBase::cast(object->elements())->length());
14117 for (uint32_t i = offset; i < length; i++) {
14118 keys->AddKey(i);
14119 }
14120 break;
14121 }
14122 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
14123 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
14124 ElementsAccessor* accessor = object->GetElementsAccessor();
14125 uint32_t length = accessor->GetCapacity(*object, object->elements());
14126 range = Min(range, length);
14127 for (uint32_t i = offset; i < range; i++) {
14128 if (accessor->HasElement(object, i)) {
14129 keys->AddKey(i);
14130 }
14131 }
14132 break;
14133 }
14134 }
14135 }
14136
14137 } // namespace
14138
14139 void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
14140 KeyAccumulator* keys,
14141 PropertyAttributes filter) {
14142 uint32_t string_keys = 0;
14143
14144 // If this is a String wrapper, add the string indices first,
14145 // as they're guaranteed to precede the elements in numerical order
14146 // and ascending order is required by ECMA-262, 6th, 9.1.12.
14147 if (object->IsJSValue()) {
14148 Object* val = JSValue::cast(*object)->value();
14149 if (val->IsString()) {
14150 String* str = String::cast(val);
14151 string_keys = str->length();
14152 for (uint32_t i = 0; i < string_keys; i++) {
14153 keys->AddKey(i);
14154 }
14155 }
14156 }
14157 CollectElementIndices(object, kMaxUInt32, keys, filter, string_keys);
14158 }
14159
14160
13977 int JSObject::GetOwnElementKeys(FixedArray* storage, 14161 int JSObject::GetOwnElementKeys(FixedArray* storage,
13978 PropertyAttributes filter) { 14162 PropertyAttributes filter) {
13979 int counter = 0; 14163 int counter = 0;
13980 14164
13981 // If this is a String wrapper, add the string indices first, 14165 // If this is a String wrapper, add the string indices first,
13982 // as they're guaranteed to preced the elements in numerical order 14166 // as they're guaranteed to precede the elements in numerical order
13983 // and ascending order is required by ECMA-262, 6th, 9.1.12. 14167 // and ascending order is required by ECMA-262, 6th, 9.1.12.
13984 if (IsJSValue()) { 14168 if (IsJSValue()) {
13985 Object* val = JSValue::cast(this)->value(); 14169 Object* val = JSValue::cast(this)->value();
13986 if (val->IsString()) { 14170 if (val->IsString()) {
13987 String* str = String::cast(val); 14171 String* str = String::cast(val);
13988 if (storage) { 14172 if (storage) {
13989 for (int i = 0; i < str->length(); i++) { 14173 for (int i = 0; i < str->length(); i++) {
13990 storage->set(counter + i, Smi::FromInt(i)); 14174 storage->set(counter + i, Smi::FromInt(i));
13991 } 14175 }
13992 } 14176 }
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
14097 } 14281 }
14098 break; 14282 break;
14099 } 14283 }
14100 } 14284 }
14101 14285
14102 DCHECK(!storage || storage->length() == counter); 14286 DCHECK(!storage || storage->length() == counter);
14103 return counter; 14287 return counter;
14104 } 14288 }
14105 14289
14106 14290
14107 int JSObject::GetEnumElementKeys(FixedArray* storage) {
14108 return GetOwnElementKeys(storage, static_cast<PropertyAttributes>(DONT_ENUM));
14109 }
14110
14111
14112 const char* Symbol::PrivateSymbolToName() const { 14291 const char* Symbol::PrivateSymbolToName() const {
14113 Heap* heap = GetIsolate()->heap(); 14292 Heap* heap = GetIsolate()->heap();
14114 #define SYMBOL_CHECK_AND_PRINT(name) \ 14293 #define SYMBOL_CHECK_AND_PRINT(name) \
14115 if (this == heap->name()) return #name; 14294 if (this == heap->name()) return #name;
14116 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT) 14295 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
14117 #undef SYMBOL_CHECK_AND_PRINT 14296 #undef SYMBOL_CHECK_AND_PRINT
14118 return "UNKNOWN"; 14297 return "UNKNOWN";
14119 } 14298 }
14120 14299
14121 14300
(...skipping 1593 matching lines...) Expand 10 before | Expand all | Expand 10 after
15715 } 15894 }
15716 } 15895 }
15717 if (sort_mode == Dictionary::SORTED) { 15896 if (sort_mode == Dictionary::SORTED) {
15718 storage->SortPairs(storage, index); 15897 storage->SortPairs(storage, index);
15719 } 15898 }
15720 DCHECK(storage->length() >= index); 15899 DCHECK(storage->length() >= index);
15721 return index - start_index; 15900 return index - start_index;
15722 } 15901 }
15723 15902
15724 15903
15904 template <typename Derived, typename Shape, typename Key>
15905 void Dictionary<Derived, Shape, Key>::CopyElementKeysTo(
15906 Handle<Derived> dictionary, KeyAccumulator* keys, PropertyAttributes filter,
15907 uint32_t start) {
15908 int capacity = dictionary->Capacity();
15909 for (int i = 0; i < capacity; i++) {
15910 Object* k = dictionary->KeyAt(i);
15911 if (!dictionary->IsKey(k) || FilterKey(k, filter)) continue;
15912 if (dictionary->IsDeleted(i)) continue;
15913 DCHECK(k->IsNumber());
15914 PropertyDetails details = dictionary->DetailsAt(i);
15915 PropertyAttributes attr = details.attributes();
15916 if ((attr & filter) != 0) continue;
15917 uint32_t index = static_cast<uint32_t>(k->Number());
15918 if (start <= index) {
15919 keys->AddKey(index);
15920 }
15921 }
15922 }
15923
15924
15725 // Backwards lookup (slow). 15925 // Backwards lookup (slow).
15726 template<typename Derived, typename Shape, typename Key> 15926 template<typename Derived, typename Shape, typename Key>
15727 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) { 15927 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
15728 int capacity = this->Capacity(); 15928 int capacity = this->Capacity();
15729 for (int i = 0; i < capacity; i++) { 15929 for (int i = 0; i < capacity; i++) {
15730 Object* k = this->KeyAt(i); 15930 Object* k = this->KeyAt(i);
15731 if (this->IsKey(k)) { 15931 if (this->IsKey(k)) {
15732 Object* e = this->ValueAt(i); 15932 Object* e = this->ValueAt(i);
15733 // TODO(dcarney): this should be templatized. 15933 // TODO(dcarney): this should be templatized.
15734 if (e->IsPropertyCell()) { 15934 if (e->IsPropertyCell()) {
(...skipping 1190 matching lines...) Expand 10 before | Expand all | Expand 10 after
16925 if (cell->value() != *new_value) { 17125 if (cell->value() != *new_value) {
16926 cell->set_value(*new_value); 17126 cell->set_value(*new_value);
16927 Isolate* isolate = cell->GetIsolate(); 17127 Isolate* isolate = cell->GetIsolate();
16928 cell->dependent_code()->DeoptimizeDependentCodeGroup( 17128 cell->dependent_code()->DeoptimizeDependentCodeGroup(
16929 isolate, DependentCode::kPropertyCellChangedGroup); 17129 isolate, DependentCode::kPropertyCellChangedGroup);
16930 } 17130 }
16931 } 17131 }
16932 17132
16933 } // namespace internal 17133 } // namespace internal
16934 } // namespace v8 17134 } // 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