Chromium Code Reviews| 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 |