Index: src/keys.cc |
diff --git a/src/keys.cc b/src/keys.cc |
index 793460c6455c24b7d27462d56c6189a02c510477..6d882663d78c18892376193616b6d22fcab51591 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); |
@@ -495,33 +519,87 @@ 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(); |
for (int i = start_index; i < limit; i++) { |
+ bool 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()) { |
@@ -538,10 +616,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. |
@@ -608,28 +686,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()); |
} |
} |