| 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 |