| Index: src/keys.cc
|
| diff --git a/src/keys.cc b/src/keys.cc
|
| index 4cbd3d895edaae7b997e01f4661fab1f6a24e3f4..abc6467989b448d87d27999e157166777bcb003b 100644
|
| --- a/src/keys.cc
|
| +++ b/src/keys.cc
|
| @@ -31,20 +31,16 @@ static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
|
| }
|
|
|
| } // namespace
|
| -
|
| MaybeHandle<FixedArray> KeyAccumulator::GetKeys(
|
| Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter,
|
| GetKeysConversion keys_conversion, bool filter_proxy_keys, bool is_for_in) {
|
| - USE(ContainsOnlyValidKeys);
|
| Isolate* isolate = object->GetIsolate();
|
| KeyAccumulator accumulator(isolate, mode, filter);
|
| accumulator.set_filter_proxy_keys(filter_proxy_keys);
|
| accumulator.set_is_for_in(is_for_in);
|
| MAYBE_RETURN(accumulator.CollectKeys(object, object),
|
| MaybeHandle<FixedArray>());
|
| - Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion);
|
| - DCHECK(ContainsOnlyValidKeys(keys));
|
| - return keys;
|
| + return accumulator.GetKeys(keys_conversion);
|
| }
|
|
|
| Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
|
| @@ -55,7 +51,11 @@ Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
|
| keys_->map() == isolate_->heap()->fixed_array_map()) {
|
| return Handle<FixedArray>::cast(keys_);
|
| }
|
| - return OrderedHashSet::ConvertToKeysArray(keys(), convert);
|
| + USE(ContainsOnlyValidKeys);
|
| + Handle<FixedArray> result =
|
| + OrderedHashSet::ConvertToKeysArray(keys(), convert);
|
| + DCHECK(ContainsOnlyValidKeys(result));
|
| + return result;
|
| }
|
|
|
| void KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) {
|
| @@ -176,6 +176,10 @@ Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
|
| if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
|
| return Nothing<bool>();
|
| }
|
| + if (!last_non_empty_prototype_.is_null() &&
|
| + *last_non_empty_prototype_ == *current) {
|
| + break;
|
| + }
|
| }
|
| return Just(true);
|
| }
|
| @@ -213,21 +217,22 @@ void FastKeyAccumulator::Prepare() {
|
| // Fully walk the prototype chain and find the last prototype with keys.
|
| is_receiver_simple_enum_ = false;
|
| has_empty_prototype_ = true;
|
| - JSReceiver* first_non_empty_prototype;
|
| + JSReceiver* last_prototype = nullptr;
|
| for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
|
| iter.Advance()) {
|
| JSReceiver* current = iter.GetCurrent<JSReceiver>();
|
| - if (CheckAndInitalizeSimpleEnumCache(current)) continue;
|
| + bool has_no_properties = CheckAndInitalizeSimpleEnumCache(current);
|
| + if (has_no_properties) continue;
|
| + last_prototype = current;
|
| has_empty_prototype_ = false;
|
| - first_non_empty_prototype = current;
|
| - // TODO(cbruni): use the first non-empty prototype.
|
| - USE(first_non_empty_prototype);
|
| - return;
|
| }
|
| - DCHECK(has_empty_prototype_);
|
| - is_receiver_simple_enum_ =
|
| - receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
|
| - !JSObject::cast(*receiver_)->HasEnumerableElements();
|
| + if (has_empty_prototype_) {
|
| + is_receiver_simple_enum_ =
|
| + receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
|
| + !JSObject::cast(*receiver_)->HasEnumerableElements();
|
| + } else if (last_prototype != nullptr) {
|
| + last_non_empty_prototype_ = handle(last_prototype, isolate_);
|
| + }
|
| }
|
|
|
| namespace {
|
| @@ -362,16 +367,18 @@ bool OnlyHasSimpleProperties(Map* map) {
|
|
|
| } // namespace
|
|
|
| -MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) {
|
| +MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(
|
| + GetKeysConversion keys_conversion) {
|
| Handle<FixedArray> keys;
|
| - if (GetKeysFast(convert).ToHandle(&keys)) {
|
| + if (filter_ == ENUMERABLE_STRINGS &&
|
| + GetKeysFast(keys_conversion).ToHandle(&keys)) {
|
| return keys;
|
| }
|
| - return GetKeysSlow(convert);
|
| + return GetKeysSlow(keys_conversion);
|
| }
|
|
|
| MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
|
| - GetKeysConversion convert) {
|
| + GetKeysConversion keys_conversion) {
|
| bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly;
|
| Map* map = receiver_->map();
|
| if (!own_only || !OnlyHasSimpleProperties(map)) {
|
| @@ -384,7 +391,7 @@ MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
|
|
|
| // Do not try to use the enum-cache for dict-mode objects.
|
| if (map->is_dictionary_map()) {
|
| - return GetOwnKeysWithElements<false>(isolate_, object, convert);
|
| + return GetOwnKeysWithElements<false>(isolate_, object, keys_conversion);
|
| }
|
| int enum_length = receiver_->map()->EnumLength();
|
| if (enum_length == kInvalidEnumCacheSentinel) {
|
| @@ -403,14 +410,19 @@ MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
|
| }
|
| // The properties-only case failed because there were probably elements on the
|
| // receiver.
|
| - return GetOwnKeysWithElements<true>(isolate_, object, convert);
|
| + return GetOwnKeysWithElements<true>(isolate_, object, keys_conversion);
|
| }
|
|
|
| MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
|
| - GetKeysConversion convert) {
|
| - return KeyAccumulator::GetKeys(receiver_, mode_, filter_,
|
| - GetKeysConversion::kKeepNumbers,
|
| - filter_proxy_keys_, is_for_in_);
|
| + GetKeysConversion keys_conversion) {
|
| + KeyAccumulator accumulator(isolate_, mode_, filter_);
|
| + accumulator.set_filter_proxy_keys(filter_proxy_keys_);
|
| + accumulator.set_is_for_in(is_for_in_);
|
| + accumulator.set_last_non_empty_prototype(last_non_empty_prototype_);
|
| +
|
| + MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_),
|
| + MaybeHandle<FixedArray>());
|
| + return accumulator.GetKeys(keys_conversion);
|
| }
|
|
|
| namespace {
|
| @@ -419,7 +431,7 @@ enum IndexedOrNamed { kIndexed, kNamed };
|
|
|
| // Returns |true| on success, |nothing| on exception.
|
| template <class Callback, IndexedOrNamed type>
|
| -Maybe<bool> GetKeysFromInterceptor(Handle<JSReceiver> receiver,
|
| +Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver,
|
| Handle<JSObject> object,
|
| KeyAccumulator* accumulator) {
|
| Isolate* isolate = accumulator->isolate();
|
| @@ -462,7 +474,7 @@ Maybe<bool> KeyAccumulator::CollectOwnElementIndices(
|
| ElementsAccessor* accessor = object->GetElementsAccessor();
|
| accessor->CollectElementIndices(object, this);
|
|
|
| - return GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback,
|
| + return CollectInterceptorKeys<v8::IndexedPropertyEnumeratorCallback,
|
| kIndexed>(receiver, object, this);
|
| }
|
|
|
| @@ -524,7 +536,7 @@ Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver,
|
| }
|
| }
|
| // Add the property keys from the interceptor.
|
| - return GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback,
|
| + return CollectInterceptorKeys<v8::GenericNamedPropertyEnumeratorCallback,
|
| kNamed>(receiver, object, this);
|
| }
|
|
|
|
|