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