[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;
|
||||
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);
|
||||
|
27
src/keys.cc
27
src/keys.cc
@ -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()) {
|
||||
|
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
|
||||
// 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);
|
||||
};
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user