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 |
(...skipping 6741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6752 for (int i = 0; i < check_limit; i++) { | 6752 for (int i = 0; i < check_limit; i++) { |
6753 Object* current = keys_->get(i); | 6753 Object* current = keys_->get(i); |
6754 if (current->KeyEquals(*key)) return; | 6754 if (current->KeyEquals(*key)) return; |
6755 } | 6755 } |
6756 EnsureCapacity(length_); | 6756 EnsureCapacity(length_); |
6757 keys_->set(length_, *key); | 6757 keys_->set(length_, *key); |
6758 length_++; | 6758 length_++; |
6759 } | 6759 } |
6760 | 6760 |
6761 | 6761 |
6762 void KeyAccumulator::AddKeys(Handle<FixedArray> array, | 6762 void KeyAccumulator::AddKeys(Handle<FixedArray> array, KeyFilter filter) { |
6763 FixedArray::KeyFilter filter) { | |
6764 int add_length = array->length(); | 6763 int add_length = array->length(); |
6765 if (add_length == 0) return; | 6764 if (add_length == 0) return; |
6766 if (keys_.is_null() && filter == FixedArray::ALL_KEYS) { | 6765 if (keys_.is_null() && filter == INCLUDE_SYMBOLS) { |
6767 keys_ = array; | 6766 keys_ = array; |
6768 length_ = keys_->length(); | 6767 length_ = keys_->length(); |
6769 return; | 6768 return; |
6770 } | 6769 } |
6771 PrepareForComparisons(add_length); | 6770 PrepareForComparisons(add_length); |
6772 int previous_key_count = length_; | 6771 int previous_key_count = length_; |
6773 for (int i = 0; i < add_length; i++) { | 6772 for (int i = 0; i < add_length; i++) { |
6774 Handle<Object> current(array->get(i), isolate_); | 6773 Handle<Object> current(array->get(i), isolate_); |
6775 if (filter == FixedArray::NON_SYMBOL_KEYS && current->IsSymbol()) continue; | 6774 if (filter == SKIP_SYMBOLS && current->IsSymbol()) continue; |
6776 AddKey(current, previous_key_count); | 6775 AddKey(current, previous_key_count); |
6777 } | 6776 } |
6778 } | 6777 } |
6779 | 6778 |
6780 | 6779 |
6781 void KeyAccumulator::AddKeys(Handle<JSObject> array_like, | 6780 void KeyAccumulator::AddKeys(Handle<JSObject> array_like, KeyFilter filter) { |
6782 FixedArray::KeyFilter filter) { | |
6783 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements()); | 6781 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements()); |
6784 ElementsAccessor* accessor = array_like->GetElementsAccessor(); | 6782 ElementsAccessor* accessor = array_like->GetElementsAccessor(); |
6785 accessor->AddElementsToKeyAccumulator(array_like, this, filter); | 6783 accessor->AddElementsToKeyAccumulator(array_like, this, filter); |
6786 } | 6784 } |
6787 | 6785 |
6788 | 6786 |
6789 void KeyAccumulator::PrepareForComparisons(int count) { | 6787 void KeyAccumulator::PrepareForComparisons(int count) { |
6790 // Depending on how many comparisons we do we should switch to the | 6788 // Depending on how many comparisons we do we should switch to the |
6791 // hash-table-based checks which have a one-time overhead for | 6789 // hash-table-based checks which have a one-time overhead for |
6792 // initializing but O(1) for HasKey checks. | 6790 // initializing but O(1) for HasKey checks. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6824 WriteBarrierMode mode = new_keys->GetWriteBarrierMode(no_gc); | 6822 WriteBarrierMode mode = new_keys->GetWriteBarrierMode(no_gc); |
6825 for (int i = 0; i < buffer_length; i++) { | 6823 for (int i = 0; i < buffer_length; i++) { |
6826 new_keys->set(i, keys_->get(i), mode); | 6824 new_keys->set(i, keys_->get(i), mode); |
6827 } | 6825 } |
6828 } | 6826 } |
6829 keys_ = new_keys; | 6827 keys_ = new_keys; |
6830 } | 6828 } |
6831 | 6829 |
6832 | 6830 |
6833 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, | 6831 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
6834 KeyCollectionType type) { | 6832 KeyCollectionType type, |
| 6833 KeyFilter filter) { |
6835 USE(ContainsOnlyValidKeys); | 6834 USE(ContainsOnlyValidKeys); |
6836 Isolate* isolate = object->GetIsolate(); | 6835 Isolate* isolate = object->GetIsolate(); |
6837 KeyAccumulator accumulator(isolate); | 6836 KeyAccumulator accumulator(isolate); |
6838 Handle<JSFunction> arguments_function( | 6837 Handle<JSFunction> arguments_function( |
6839 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); | 6838 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); |
6840 | 6839 |
6841 PrototypeIterator::WhereToEnd end = type == OWN_ONLY | 6840 PrototypeIterator::WhereToEnd end = type == OWN_ONLY |
6842 ? PrototypeIterator::END_AT_NON_HIDDEN | 6841 ? PrototypeIterator::END_AT_NON_HIDDEN |
6843 : PrototypeIterator::END_AT_NULL; | 6842 : PrototypeIterator::END_AT_NULL; |
6844 // Only collect keys if access is permitted. | 6843 // Only collect keys if access is permitted. |
6845 for (PrototypeIterator iter(isolate, object, | 6844 for (PrototypeIterator iter(isolate, object, |
6846 PrototypeIterator::START_AT_RECEIVER); | 6845 PrototypeIterator::START_AT_RECEIVER); |
6847 !iter.IsAtEnd(end); iter.Advance()) { | 6846 !iter.IsAtEnd(end); iter.Advance()) { |
6848 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | 6847 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
6849 Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter); | 6848 Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter); |
6850 Handle<Object> args[] = { proxy }; | 6849 Handle<Object> args[] = { proxy }; |
6851 Handle<Object> names; | 6850 Handle<Object> names; |
6852 ASSIGN_RETURN_ON_EXCEPTION( | 6851 ASSIGN_RETURN_ON_EXCEPTION( |
6853 isolate, names, | 6852 isolate, names, |
6854 Execution::Call(isolate, | 6853 Execution::Call(isolate, |
6855 isolate->proxy_enumerate(), | 6854 isolate->proxy_enumerate(), |
6856 object, | 6855 object, |
6857 arraysize(args), | 6856 arraysize(args), |
6858 args), | 6857 args), |
6859 FixedArray); | 6858 FixedArray); |
6860 accumulator.AddKeys(Handle<JSObject>::cast(names), FixedArray::ALL_KEYS); | 6859 accumulator.AddKeys(Handle<JSObject>::cast(names), filter); |
6861 break; | 6860 break; |
6862 } | 6861 } |
6863 | 6862 |
6864 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); | 6863 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); |
6865 | 6864 |
6866 // Check access rights if required. | 6865 // Check access rights if required. |
6867 if (current->IsAccessCheckNeeded() && !isolate->MayAccess(current)) { | 6866 if (current->IsAccessCheckNeeded() && !isolate->MayAccess(current)) { |
6868 if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | 6867 if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
6869 isolate->ReportFailedAccessCheck(current); | 6868 isolate->ReportFailedAccessCheck(current); |
6870 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); | 6869 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); |
6871 } | 6870 } |
6872 break; | 6871 break; |
6873 } | 6872 } |
6874 | 6873 |
6875 // Compute the element keys. | 6874 // Compute the element keys. |
6876 Handle<FixedArray> element_keys = | 6875 Handle<FixedArray> element_keys = |
6877 isolate->factory()->NewFixedArray(current->NumberOfEnumElements()); | 6876 isolate->factory()->NewFixedArray(current->NumberOfEnumElements()); |
6878 current->GetEnumElementKeys(*element_keys); | 6877 current->GetEnumElementKeys(*element_keys); |
6879 accumulator.AddKeys(element_keys, FixedArray::ALL_KEYS); | 6878 accumulator.AddKeys(element_keys, filter); |
6880 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | 6879 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); |
6881 | 6880 |
6882 // Add the element keys from the interceptor. | 6881 // Add the element keys from the interceptor. |
6883 if (current->HasIndexedInterceptor()) { | 6882 if (current->HasIndexedInterceptor()) { |
6884 Handle<JSObject> result; | 6883 Handle<JSObject> result; |
6885 if (JSObject::GetKeysForIndexedInterceptor( | 6884 if (JSObject::GetKeysForIndexedInterceptor( |
6886 current, object).ToHandle(&result)) { | 6885 current, object).ToHandle(&result)) { |
6887 accumulator.AddKeys(result, FixedArray::ALL_KEYS); | 6886 accumulator.AddKeys(result, filter); |
6888 } | 6887 } |
6889 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | 6888 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); |
6890 } | 6889 } |
6891 | 6890 |
6892 // We can cache the computed property keys if access checks are | 6891 if (filter == SKIP_SYMBOLS) { |
6893 // not needed and no interceptors are involved. | 6892 // We can cache the computed property keys if access checks are |
6894 // | 6893 // not needed and no interceptors are involved. |
6895 // We do not use the cache if the object has elements and | 6894 // |
6896 // therefore it does not make sense to cache the property names | 6895 // We do not use the cache if the object has elements and |
6897 // for arguments objects. Arguments objects will always have | 6896 // therefore it does not make sense to cache the property names |
6898 // elements. | 6897 // for arguments objects. Arguments objects will always have |
6899 // Wrapped strings have elements, but don't have an elements | 6898 // elements. |
6900 // array or dictionary. So the fast inline test for whether to | 6899 // Wrapped strings have elements, but don't have an elements |
6901 // use the cache says yes, so we should not create a cache. | 6900 // array or dictionary. So the fast inline test for whether to |
6902 bool cache_enum_length = | 6901 // use the cache says yes, so we should not create a cache. |
6903 ((current->map()->GetConstructor() != *arguments_function) && | 6902 bool cache_enum_length = |
6904 !current->IsJSValue() && !current->IsAccessCheckNeeded() && | 6903 ((current->map()->GetConstructor() != *arguments_function) && |
6905 !current->HasNamedInterceptor() && !current->HasIndexedInterceptor()); | 6904 !current->IsJSValue() && !current->IsAccessCheckNeeded() && |
6906 // Compute the property keys and cache them if possible. | 6905 !current->HasNamedInterceptor() && |
| 6906 !current->HasIndexedInterceptor()); |
| 6907 // Compute the property keys and cache them if possible. |
6907 | 6908 |
6908 Handle<FixedArray> enum_keys = | 6909 Handle<FixedArray> enum_keys = |
6909 JSObject::GetEnumPropertyKeys(current, cache_enum_length); | 6910 JSObject::GetEnumPropertyKeys(current, cache_enum_length); |
6910 accumulator.AddKeys(enum_keys, FixedArray::ALL_KEYS); | 6911 accumulator.AddKeys(enum_keys, filter); |
| 6912 } else { |
| 6913 DCHECK(filter == INCLUDE_SYMBOLS); |
| 6914 PropertyAttributes attr_filter = |
| 6915 static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL); |
| 6916 Handle<FixedArray> property_keys = isolate->factory()->NewFixedArray( |
| 6917 current->NumberOfOwnProperties(attr_filter)); |
| 6918 current->GetOwnPropertyNames(*property_keys, 0, attr_filter); |
| 6919 accumulator.AddKeys(property_keys, filter); |
| 6920 } |
6911 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | 6921 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); |
6912 | 6922 |
6913 // Add the non-symbol property keys from the interceptor. | 6923 // Add the property keys from the interceptor. |
6914 if (current->HasNamedInterceptor()) { | 6924 if (current->HasNamedInterceptor()) { |
6915 Handle<JSObject> result; | 6925 Handle<JSObject> result; |
6916 if (JSObject::GetKeysForNamedInterceptor( | 6926 if (JSObject::GetKeysForNamedInterceptor( |
6917 current, object).ToHandle(&result)) { | 6927 current, object).ToHandle(&result)) { |
6918 accumulator.AddKeys(result, FixedArray::NON_SYMBOL_KEYS); | 6928 accumulator.AddKeys(result, filter); |
6919 } | 6929 } |
6920 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | 6930 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); |
6921 } | 6931 } |
6922 } | 6932 } |
6923 | 6933 |
6924 Handle<FixedArray> keys = accumulator.GetKeys(); | 6934 Handle<FixedArray> keys = accumulator.GetKeys(); |
6925 DCHECK(ContainsOnlyValidKeys(keys)); | 6935 DCHECK(ContainsOnlyValidKeys(keys)); |
6926 return keys; | 6936 return keys; |
6927 } | 6937 } |
6928 | 6938 |
(...skipping 6897 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13826 return global_dictionary()->CopyKeysTo(storage, index, filter, | 13836 return global_dictionary()->CopyKeysTo(storage, index, filter, |
13827 GlobalDictionary::UNSORTED); | 13837 GlobalDictionary::UNSORTED); |
13828 } else { | 13838 } else { |
13829 return property_dictionary()->CopyKeysTo(storage, index, filter, | 13839 return property_dictionary()->CopyKeysTo(storage, index, filter, |
13830 NameDictionary::UNSORTED); | 13840 NameDictionary::UNSORTED); |
13831 } | 13841 } |
13832 } | 13842 } |
13833 | 13843 |
13834 | 13844 |
13835 int JSObject::NumberOfOwnElements(PropertyAttributes filter) { | 13845 int JSObject::NumberOfOwnElements(PropertyAttributes filter) { |
13836 return GetOwnElementKeys(NULL, filter); | |
13837 } | |
13838 | |
13839 | |
13840 int JSObject::NumberOfEnumElements() { | |
13841 // Fast case for objects with no elements. | 13846 // Fast case for objects with no elements. |
13842 if (!IsJSValue() && HasFastObjectElements()) { | 13847 if (!IsJSValue() && HasFastElements()) { |
13843 uint32_t length = IsJSArray() ? | 13848 uint32_t length = IsJSArray() ? |
13844 static_cast<uint32_t>( | 13849 static_cast<uint32_t>( |
13845 Smi::cast(JSArray::cast(this)->length())->value()) : | 13850 Smi::cast(JSArray::cast(this)->length())->value()) : |
13846 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 13851 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
13847 if (length == 0) return 0; | 13852 if (length == 0) return 0; |
13848 } | 13853 } |
13849 // Compute the number of enumerable elements. | 13854 // Compute the number of enumerable elements. |
| 13855 return GetOwnElementKeys(NULL, filter); |
| 13856 } |
| 13857 |
| 13858 |
| 13859 int JSObject::NumberOfEnumElements() { |
13850 return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM)); | 13860 return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM)); |
13851 } | 13861 } |
13852 | 13862 |
13853 | 13863 |
13854 int JSObject::GetOwnElementKeys(FixedArray* storage, | 13864 int JSObject::GetOwnElementKeys(FixedArray* storage, |
13855 PropertyAttributes filter) { | 13865 PropertyAttributes filter) { |
13856 int counter = 0; | 13866 int counter = 0; |
13857 | 13867 |
13858 // If this is a String wrapper, add the string indices first, | 13868 // If this is a String wrapper, add the string indices first, |
13859 // as they're guaranteed to preced the elements in numerical order | 13869 // as they're guaranteed to preced the elements in numerical order |
(...skipping 2942 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16802 if (cell->value() != *new_value) { | 16812 if (cell->value() != *new_value) { |
16803 cell->set_value(*new_value); | 16813 cell->set_value(*new_value); |
16804 Isolate* isolate = cell->GetIsolate(); | 16814 Isolate* isolate = cell->GetIsolate(); |
16805 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16815 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
16806 isolate, DependentCode::kPropertyCellChangedGroup); | 16816 isolate, DependentCode::kPropertyCellChangedGroup); |
16807 } | 16817 } |
16808 } | 16818 } |
16809 | 16819 |
16810 } // namespace internal | 16820 } // namespace internal |
16811 } // namespace v8 | 16821 } // namespace v8 |
OLD | NEW |