[keys] Postpone shadowed key checking in the KeyAccumulator

Only start checking if new keys are shadowed after the first prototype has added
non-enumerable shadow keys. This helps minimally in some corner cases if there
are few enumerable properties on the prototype compared to the receiver.

BUG=chromium:628173

Review-Url: https://codereview.chromium.org/2169523002
Cr-Commit-Position: refs/heads/master@{#37940}
This commit is contained in:
cbruni 2016-07-21 04:05:16 -07:00 committed by Commit bot
parent ff0b6d49ce
commit 211615d41e
4 changed files with 26 additions and 17 deletions

View File

@ -1375,7 +1375,7 @@ class DictionaryElementsAccessor
if (!dictionary->IsKey(isolate, raw_key)) continue; if (!dictionary->IsKey(isolate, raw_key)) continue;
uint32_t key = FilterKey(dictionary, i, raw_key, filter); uint32_t key = FilterKey(dictionary, i, raw_key, filter);
if (key == kMaxUInt32) { if (key == kMaxUInt32) {
keys->AddShadowKey(raw_key); keys->AddShadowingKey(raw_key);
continue; continue;
} }
elements->set(insertion_index, raw_key); elements->set(insertion_index, raw_key);

View File

@ -117,7 +117,7 @@ MaybeHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator,
MAYBE_RETURN(found, MaybeHandle<FixedArray>()); MAYBE_RETURN(found, MaybeHandle<FixedArray>());
if (!found.FromJust()) continue; if (!found.FromJust()) continue;
if (!desc.enumerable()) { if (!desc.enumerable()) {
accumulator->AddShadowKey(key); accumulator->AddShadowingKey(key);
continue; continue;
} }
} }
@ -166,6 +166,9 @@ Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
: PrototypeIterator::END_AT_NULL; : PrototypeIterator::END_AT_NULL;
for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end); for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end);
!iter.IsAtEnd();) { !iter.IsAtEnd();) {
// Start the shadow checks only after the first prototype has added
// shadowing keys.
if (HasShadowingKeys()) skip_shadow_check_ = false;
Handle<JSReceiver> current = Handle<JSReceiver> current =
PrototypeIterator::GetCurrent<JSReceiver>(iter); PrototypeIterator::GetCurrent<JSReceiver>(iter);
Maybe<bool> result = Just(false); // Dummy initialization. Maybe<bool> result = Just(false); // Dummy initialization.
@ -190,21 +193,23 @@ Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
return Just(true); return Just(true);
} }
bool KeyAccumulator::HasShadowingKeys() { return !shadowing_keys_.is_null(); }
bool KeyAccumulator::IsShadowed(Handle<Object> key) { bool KeyAccumulator::IsShadowed(Handle<Object> key) {
if (shadowed_keys_.is_null()) return false; if (!HasShadowingKeys() || skip_shadow_check_) return false;
return shadowed_keys_->Has(isolate_, key); return shadowing_keys_->Has(isolate_, key);
} }
void KeyAccumulator::AddShadowKey(Object* key) { void KeyAccumulator::AddShadowingKey(Object* key) {
if (mode_ == KeyCollectionMode::kOwnOnly) return; if (mode_ == KeyCollectionMode::kOwnOnly) return;
AddShadowKey(handle(key, isolate_)); AddShadowingKey(handle(key, isolate_));
} }
void KeyAccumulator::AddShadowKey(Handle<Object> key) { void KeyAccumulator::AddShadowingKey(Handle<Object> key) {
if (mode_ == KeyCollectionMode::kOwnOnly) return; if (mode_ == KeyCollectionMode::kOwnOnly) return;
if (shadowed_keys_.is_null()) { if (shadowing_keys_.is_null()) {
shadowed_keys_ = ObjectHashSet::New(isolate_, 16); shadowing_keys_ = ObjectHashSet::New(isolate_, 16);
} }
shadowed_keys_ = ObjectHashSet::Add(shadowed_keys_, key); shadowing_keys_ = ObjectHashSet::Add(shadowing_keys_, key);
} }
namespace { namespace {
@ -548,7 +553,7 @@ int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
if (key->FilterKey(keys->filter())) continue; if (key->FilterKey(keys->filter())) continue;
if (is_shadowing_key) { if (is_shadowing_key) {
keys->AddShadowKey(key); keys->AddShadowingKey(key);
} else { } else {
keys->AddKey(key, DO_NOT_CONVERT); keys->AddKey(key, DO_NOT_CONVERT);
} }
@ -590,7 +595,7 @@ Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver,
PropertyDetails details = descs->GetDetails(i); PropertyDetails details = descs->GetDetails(i);
if (!details.IsDontEnum()) continue; if (!details.IsDontEnum()) continue;
Object* key = descs->GetKey(i); Object* key = descs->GetKey(i);
this->AddShadowKey(key); this->AddShadowingKey(key);
} }
} }
} else if (object->IsJSGlobalObject()) { } else if (object->IsJSGlobalObject()) {

View File

@ -83,8 +83,8 @@ class KeyAccumulator final BASE_EMBEDDED {
} }
// Shadowing keys are used to filter keys. This happens when non-enumerable // Shadowing keys are used to filter keys. This happens when non-enumerable
// keys appear again on the prototype chain. // keys appear again on the prototype chain.
void AddShadowKey(Object* key); void AddShadowingKey(Object* key);
void AddShadowKey(Handle<Object> key); void AddShadowingKey(Handle<Object> key);
private: private:
Maybe<bool> CollectOwnKeys(Handle<JSReceiver> receiver, Maybe<bool> CollectOwnKeys(Handle<JSReceiver> receiver,
@ -96,6 +96,7 @@ class KeyAccumulator final BASE_EMBEDDED {
Maybe<bool> AddKeysFromJSProxy(Handle<JSProxy> proxy, Maybe<bool> AddKeysFromJSProxy(Handle<JSProxy> proxy,
Handle<FixedArray> keys); Handle<FixedArray> keys);
bool IsShadowed(Handle<Object> key); bool IsShadowed(Handle<Object> key);
bool HasShadowingKeys();
Handle<OrderedHashSet> keys() { return Handle<OrderedHashSet>::cast(keys_); } Handle<OrderedHashSet> keys() { return Handle<OrderedHashSet>::cast(keys_); }
Isolate* isolate_; Isolate* isolate_;
@ -104,12 +105,15 @@ class KeyAccumulator final BASE_EMBEDDED {
// result list, a FixedArray containing all collected keys. // result list, a FixedArray containing all collected keys.
Handle<FixedArray> keys_; Handle<FixedArray> keys_;
Handle<JSReceiver> last_non_empty_prototype_; Handle<JSReceiver> last_non_empty_prototype_;
Handle<ObjectHashSet> shadowed_keys_; Handle<ObjectHashSet> shadowing_keys_;
KeyCollectionMode mode_; KeyCollectionMode mode_;
PropertyFilter filter_; PropertyFilter filter_;
bool filter_proxy_keys_ = true; bool filter_proxy_keys_ = true;
bool is_for_in_ = false; bool is_for_in_ = false;
bool skip_indices_ = false; bool skip_indices_ = false;
// For all the keys on the first receiver adding a shadowing key we can skip
// the shadow check.
bool skip_shadow_check_ = true;
DISALLOW_COPY_AND_ASSIGN(KeyAccumulator); DISALLOW_COPY_AND_ASSIGN(KeyAccumulator);
}; };

View File

@ -17537,7 +17537,7 @@ void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
} }
if (dictionary->IsDeleted(i)) continue; if (dictionary->IsDeleted(i)) continue;
if (is_shadowing_key) { if (is_shadowing_key) {
accumulator->AddShadowKey(key); accumulator->AddShadowingKey(key);
continue; continue;
} else { } else {
storage->set(properties, Smi::FromInt(i)); storage->set(properties, Smi::FromInt(i));
@ -17577,7 +17577,7 @@ void Dictionary<Derived, Shape, Key>::CollectKeysTo(
if (raw_dict->IsDeleted(i)) continue; if (raw_dict->IsDeleted(i)) continue;
PropertyDetails details = raw_dict->DetailsAt(i); PropertyDetails details = raw_dict->DetailsAt(i);
if ((details.attributes() & filter) != 0) { if ((details.attributes() & filter) != 0) {
keys->AddShadowKey(k); keys->AddShadowingKey(k);
continue; continue;
} }
if (filter & ONLY_ALL_CAN_READ) { if (filter & ONLY_ALL_CAN_READ) {