[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;
uint32_t key = FilterKey(dictionary, i, raw_key, filter);
if (key == kMaxUInt32) {
keys->AddShadowKey(raw_key);
keys->AddShadowingKey(raw_key);
continue;
}
elements->set(insertion_index, raw_key);

View File

@ -117,7 +117,7 @@ MaybeHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator,
MAYBE_RETURN(found, MaybeHandle<FixedArray>());
if (!found.FromJust()) continue;
if (!desc.enumerable()) {
accumulator->AddShadowKey(key);
accumulator->AddShadowingKey(key);
continue;
}
}
@ -166,6 +166,9 @@ Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
: PrototypeIterator::END_AT_NULL;
for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end);
!iter.IsAtEnd();) {
// Start the shadow checks only after the first prototype has added
// shadowing keys.
if (HasShadowingKeys()) skip_shadow_check_ = false;
Handle<JSReceiver> current =
PrototypeIterator::GetCurrent<JSReceiver>(iter);
Maybe<bool> result = Just(false); // Dummy initialization.
@ -190,21 +193,23 @@ Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
return Just(true);
}
bool KeyAccumulator::HasShadowingKeys() { return !shadowing_keys_.is_null(); }
bool KeyAccumulator::IsShadowed(Handle<Object> key) {
if (shadowed_keys_.is_null()) return false;
return shadowed_keys_->Has(isolate_, key);
if (!HasShadowingKeys() || skip_shadow_check_) return false;
return shadowing_keys_->Has(isolate_, key);
}
void KeyAccumulator::AddShadowKey(Object* key) {
void KeyAccumulator::AddShadowingKey(Object* key) {
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 (shadowed_keys_.is_null()) {
shadowed_keys_ = ObjectHashSet::New(isolate_, 16);
if (shadowing_keys_.is_null()) {
shadowing_keys_ = ObjectHashSet::New(isolate_, 16);
}
shadowed_keys_ = ObjectHashSet::Add(shadowed_keys_, key);
shadowing_keys_ = ObjectHashSet::Add(shadowing_keys_, key);
}
namespace {
@ -548,7 +553,7 @@ int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
if (key->FilterKey(keys->filter())) continue;
if (is_shadowing_key) {
keys->AddShadowKey(key);
keys->AddShadowingKey(key);
} else {
keys->AddKey(key, DO_NOT_CONVERT);
}
@ -590,7 +595,7 @@ Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver,
PropertyDetails details = descs->GetDetails(i);
if (!details.IsDontEnum()) continue;
Object* key = descs->GetKey(i);
this->AddShadowKey(key);
this->AddShadowingKey(key);
}
}
} 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
// keys appear again on the prototype chain.
void AddShadowKey(Object* key);
void AddShadowKey(Handle<Object> key);
void AddShadowingKey(Object* key);
void AddShadowingKey(Handle<Object> key);
private:
Maybe<bool> CollectOwnKeys(Handle<JSReceiver> receiver,
@ -96,6 +96,7 @@ class KeyAccumulator final BASE_EMBEDDED {
Maybe<bool> AddKeysFromJSProxy(Handle<JSProxy> proxy,
Handle<FixedArray> keys);
bool IsShadowed(Handle<Object> key);
bool HasShadowingKeys();
Handle<OrderedHashSet> keys() { return Handle<OrderedHashSet>::cast(keys_); }
Isolate* isolate_;
@ -104,12 +105,15 @@ class KeyAccumulator final BASE_EMBEDDED {
// result list, a FixedArray containing all collected keys.
Handle<FixedArray> keys_;
Handle<JSReceiver> last_non_empty_prototype_;
Handle<ObjectHashSet> shadowed_keys_;
Handle<ObjectHashSet> shadowing_keys_;
KeyCollectionMode mode_;
PropertyFilter filter_;
bool filter_proxy_keys_ = true;
bool is_for_in_ = 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);
};

View File

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