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 |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |