[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:
parent
ff0b6d49ce
commit
211615d41e
@ -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);
|
||||||
|
27
src/keys.cc
27
src/keys.cc
@ -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()) {
|
||||||
|
10
src/keys.h
10
src/keys.h
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user