Chromium Code Reviews| Index: src/keys.cc |
| diff --git a/src/keys.cc b/src/keys.cc |
| index eee015075a584871fcb0aba448d63aca94601740..09a2d7a20af042defa519d20c344cc31aa09dd92 100644 |
| --- a/src/keys.cc |
| +++ b/src/keys.cc |
| @@ -69,6 +69,7 @@ void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { |
| } else if (filter_ & SKIP_STRINGS) { |
| return; |
| } |
| + if (IsShadowed(key)) return; |
| if (keys_.is_null()) { |
| keys_ = OrderedHashSet::Allocate(isolate_, 16); |
| } |
| @@ -96,13 +97,15 @@ void KeyAccumulator::AddKeys(Handle<JSObject> array_like, |
| accessor->AddElementsToKeyAccumulator(array_like, this, convert); |
| } |
| -MaybeHandle<FixedArray> FilterProxyKeys(Isolate* isolate, Handle<JSProxy> owner, |
| +MaybeHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator, |
| + Handle<JSProxy> owner, |
| Handle<FixedArray> keys, |
| PropertyFilter filter) { |
| if (filter == ALL_PROPERTIES) { |
| // Nothing to do. |
| return keys; |
| } |
| + Isolate* isolate = accumulator->isolate(); |
| int store_position = 0; |
| for (int i = 0; i < keys->length(); ++i) { |
| Handle<Name> key(Name::cast(keys->get(i)), isolate); |
| @@ -112,7 +115,11 @@ MaybeHandle<FixedArray> FilterProxyKeys(Isolate* isolate, Handle<JSProxy> owner, |
| Maybe<bool> found = |
| JSProxy::GetOwnPropertyDescriptor(isolate, owner, key, &desc); |
| MAYBE_RETURN(found, MaybeHandle<FixedArray>()); |
| - if (!found.FromJust() || !desc.enumerable()) continue; // Skip this key. |
| + if (!found.FromJust()) continue; |
| + if (!desc.enumerable()) { |
| + accumulator->AddShadowKey(key); |
| + continue; |
| + } |
| } |
| // Keep this key. |
| if (store_position != i) { |
| @@ -131,7 +138,7 @@ Maybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy, |
| if (filter_proxy_keys_) { |
| DCHECK(!is_for_in_); |
| ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| - isolate_, keys, FilterProxyKeys(isolate_, proxy, keys, filter_), |
| + isolate_, keys, FilterProxyKeys(this, proxy, keys, filter_), |
| Nothing<bool>()); |
| } |
| if (mode_ == KeyCollectionMode::kOwnOnly && !is_for_in_) { |
| @@ -183,6 +190,23 @@ Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver, |
| return Just(true); |
| } |
| +bool KeyAccumulator::IsShadowed(Handle<Object> key) { |
| + if (shadowed_keys_.is_null()) return false; |
| + return shadowed_keys_->Has(isolate_, key); |
| +} |
| + |
| +void KeyAccumulator::AddShadowKey(Object* key) { |
| + if (mode_ == KeyCollectionMode::kOwnOnly) return; |
| + AddShadowKey(handle(key, isolate_)); |
| +} |
| +void KeyAccumulator::AddShadowKey(Handle<Object> key) { |
| + if (mode_ == KeyCollectionMode::kOwnOnly) return; |
| + if (shadowed_keys_.is_null()) { |
| + shadowed_keys_ = ObjectHashSet::New(isolate_, 16); |
| + } |
| + shadowed_keys_ = ObjectHashSet::Add(shadowed_keys_, key); |
| +} |
| + |
| namespace { |
| void TrySettingEmptyEnumCache(JSReceiver* object) { |
| @@ -329,7 +353,7 @@ Handle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, |
| keys = GetFastEnumPropertyKeys(isolate, object); |
| } else { |
| // TODO(cbruni): preallocate big enough array to also hold elements. |
| - keys = KeyAccumulator::GetEnumPropertyKeys(isolate, object); |
| + keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate, object); |
| } |
| Handle<FixedArray> result = |
| accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE); |
| @@ -485,33 +509,88 @@ int CollectOwnPropertyNamesInternal(Handle<JSObject> object, |
| Handle<DescriptorArray> descs, |
| int start_index, int limit) { |
| int first_skipped = -1; |
| + PropertyFilter filter = keys->filter(); |
| + KeyCollectionMode mode = keys->mode(); |
| + bool is_shadowing_key = false; |
|
adamk
2016/06/27 19:19:33
This declaration seems like it'd be clearer inside
Camillo Bruni
2016/06/29 17:27:56
pushing it into the loop
|
| for (int i = start_index; i < limit; i++) { |
| + is_shadowing_key = false; |
| PropertyDetails details = descs->GetDetails(i); |
| - if ((details.attributes() & keys->filter()) != 0) continue; |
| - if (keys->filter() & ONLY_ALL_CAN_READ) { |
| + |
| + if ((details.attributes() & filter) != 0) { |
| + if (mode == KeyCollectionMode::kIncludePrototypes) { |
| + is_shadowing_key = true; |
| + } else { |
| + continue; |
| + } |
| + } |
| + |
| + if (filter & ONLY_ALL_CAN_READ) { |
| if (details.kind() != kAccessor) continue; |
| Object* accessors = descs->GetValue(i); |
| if (!accessors->IsAccessorInfo()) continue; |
| if (!AccessorInfo::cast(accessors)->all_can_read()) continue; |
| } |
| + |
| Name* key = descs->GetKey(i); |
| if (skip_symbols == key->IsSymbol()) { |
| if (first_skipped == -1) first_skipped = i; |
| continue; |
| } |
| if (key->FilterKey(keys->filter())) continue; |
| - keys->AddKey(key, DO_NOT_CONVERT); |
| + |
| + if (is_shadowing_key) { |
| + keys->AddShadowKey(key); |
| + } else { |
| + keys->AddKey(key, DO_NOT_CONVERT); |
| + } |
| } |
| return first_skipped; |
| } |
| +template <class T> |
| +Handle<FixedArray> GetOwnEnumPropertyDictionaryKeys(Isolate* isolate, |
| + KeyCollectionMode mode, |
| + KeyAccumulator* accumulator, |
| + Handle<JSObject> object, |
| + T* raw_dictionary) { |
| + Handle<T> dictionary(raw_dictionary, isolate); |
| + int length = dictionary->NumberOfEnumElements(); |
| + if (length == 0) { |
| + return isolate->factory()->empty_fixed_array(); |
| + } |
| + Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
| + T::CopyEnumKeysTo(dictionary, storage, mode, accumulator); |
| + return storage; |
| +} |
| } // namespace |
| Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver, |
| Handle<JSObject> object) { |
| if (filter_ == ENUMERABLE_STRINGS) { |
| - Handle<FixedArray> enum_keys = |
| - KeyAccumulator::GetEnumPropertyKeys(isolate_, object); |
| + Handle<FixedArray> enum_keys; |
| + if (object->HasFastProperties()) { |
| + enum_keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, object); |
| + // If the number of properties equals the length of enumerable properties |
| + // we do not have to filter out non-enumerable ones |
| + Map* map = object->map(); |
| + int nof_descriptors = map->NumberOfOwnDescriptors(); |
| + if (enum_keys->length() != nof_descriptors) { |
| + Handle<DescriptorArray> descs = |
| + Handle<DescriptorArray>(map->instance_descriptors(), isolate_); |
| + for (int i = 0; i < nof_descriptors; i++) { |
| + PropertyDetails details = descs->GetDetails(i); |
| + if (!details.IsDontEnum()) continue; |
| + Object* key = descs->GetKey(i); |
| + this->AddShadowKey(key); |
| + } |
| + } |
| + } else if (object->IsJSGlobalObject()) { |
| + enum_keys = GetOwnEnumPropertyDictionaryKeys( |
| + isolate_, mode_, this, object, object->global_dictionary()); |
| + } else { |
| + enum_keys = GetOwnEnumPropertyDictionaryKeys( |
| + isolate_, mode_, this, object, object->property_dictionary()); |
| + } |
| AddKeys(enum_keys, DO_NOT_CONVERT); |
| } else { |
| if (object->HasFastProperties()) { |
| @@ -528,10 +607,10 @@ Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver, |
| } |
| } else if (object->IsJSGlobalObject()) { |
| GlobalDictionary::CollectKeysTo( |
| - handle(object->global_dictionary(), isolate_), this, filter_); |
| + handle(object->global_dictionary(), isolate_), this); |
| } else { |
| NameDictionary::CollectKeysTo( |
| - handle(object->property_dictionary(), isolate_), this, filter_); |
| + handle(object->property_dictionary(), isolate_), this); |
| } |
| } |
| // Add the property keys from the interceptor. |
| @@ -561,28 +640,18 @@ Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, |
| } |
| // static |
| -Handle<FixedArray> KeyAccumulator::GetEnumPropertyKeys( |
| +Handle<FixedArray> KeyAccumulator::GetOwnEnumPropertyKeys( |
| Isolate* isolate, Handle<JSObject> object) { |
| if (object->HasFastProperties()) { |
| return GetFastEnumPropertyKeys(isolate, object); |
| } else if (object->IsJSGlobalObject()) { |
| - Handle<GlobalDictionary> dictionary(object->global_dictionary(), isolate); |
| - int length = dictionary->NumberOfEnumElements(); |
| - if (length == 0) { |
| - return isolate->factory()->empty_fixed_array(); |
| - } |
| - Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
| - dictionary->CopyEnumKeysTo(*storage); |
| - return storage; |
| + return GetOwnEnumPropertyDictionaryKeys( |
| + isolate, KeyCollectionMode::kOwnOnly, nullptr, object, |
| + object->global_dictionary()); |
| } else { |
| - Handle<NameDictionary> dictionary(object->property_dictionary(), isolate); |
| - int length = dictionary->NumberOfEnumElements(); |
| - if (length == 0) { |
| - return isolate->factory()->empty_fixed_array(); |
| - } |
| - Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
| - dictionary->CopyEnumKeysTo(*storage); |
| - return storage; |
| + return GetOwnEnumPropertyDictionaryKeys( |
| + isolate, KeyCollectionMode::kOwnOnly, nullptr, object, |
| + object->property_dictionary()); |
| } |
| } |