LCOV - code coverage report
Current view: top level - src - keys.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 342 346 98.8 %
Date: 2017-10-20 Functions: 38 39 97.4 %

          Line data    Source code
       1             : // Copyright 2013 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/keys.h"
       6             : 
       7             : #include "src/api-arguments-inl.h"
       8             : #include "src/elements.h"
       9             : #include "src/factory.h"
      10             : #include "src/identity-map.h"
      11             : #include "src/isolate-inl.h"
      12             : #include "src/objects-inl.h"
      13             : #include "src/property-descriptor.h"
      14             : #include "src/prototype.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : 
      19     5232455 : KeyAccumulator::~KeyAccumulator() {
      20     5232455 : }
      21             : 
      22             : namespace {
      23             : 
      24             : static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
      25             :   int len = array->length();
      26             :   for (int i = 0; i < len; i++) {
      27             :     Object* e = array->get(i);
      28             :     if (!(e->IsName() || e->IsNumber())) return false;
      29             :   }
      30             :   return true;
      31             : }
      32             : 
      33             : }  // namespace
      34             : 
      35             : // static
      36     1330471 : MaybeHandle<FixedArray> KeyAccumulator::GetKeys(
      37             :     Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter,
      38             :     GetKeysConversion keys_conversion, bool is_for_in) {
      39             :   Isolate* isolate = object->GetIsolate();
      40             :   FastKeyAccumulator accumulator(isolate, object, mode, filter);
      41             :   accumulator.set_is_for_in(is_for_in);
      42     1330471 :   return accumulator.GetKeys(keys_conversion);
      43             : }
      44             : 
      45     5437429 : Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
      46             :   if (keys_.is_null()) {
      47       60590 :     return isolate_->factory()->empty_fixed_array();
      48             :   }
      49     5522587 :   if (mode_ == KeyCollectionMode::kOwnOnly &&
      50      145748 :       keys_->map() == isolate_->heap()->fixed_array_map()) {
      51             :     return Handle<FixedArray>::cast(keys_);
      52             :   }
      53             :   USE(ContainsOnlyValidKeys);
      54             :   Handle<FixedArray> result =
      55     5375343 :       OrderedHashSet::ConvertToKeysArray(keys(), convert);
      56             :   DCHECK(ContainsOnlyValidKeys(result));
      57     5375343 :   return result;
      58             : }
      59             : 
      60     2989853 : void KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) {
      61     5979706 :   AddKey(handle(key, isolate_), convert);
      62     2989853 : }
      63             : 
      64    46791437 : void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
      65    46791437 :   if (key->IsSymbol()) {
      66       34035 :     if (filter_ & SKIP_SYMBOLS) return;
      67       23775 :     if (Handle<Symbol>::cast(key)->is_private()) return;
      68    46767650 :   } else if (filter_ & SKIP_STRINGS) {
      69             :     return;
      70             :   }
      71    46791419 :   if (IsShadowed(key)) return;
      72    46781189 :   if (keys_.is_null()) {
      73     5375376 :     keys_ = OrderedHashSet::Allocate(isolate_, 16);
      74             :   }
      75             :   uint32_t index;
      76    46783267 :   if (convert == CONVERT_TO_ARRAY_INDEX && key->IsString() &&
      77         715 :       Handle<String>::cast(key)->AsArrayIndex(&index)) {
      78          99 :     key = isolate_->factory()->NewNumberFromUint(index);
      79             :   }
      80    46781189 :   keys_ = OrderedHashSet::Add(keys(), key);
      81             : }
      82             : 
      83     9058855 : void KeyAccumulator::AddKeys(Handle<FixedArray> array,
      84             :                              AddKeyConversion convert) {
      85             :   int add_length = array->length();
      86    52603611 :   for (int i = 0; i < add_length; i++) {
      87    43544756 :     Handle<Object> current(array->get(i), isolate_);
      88    43544756 :     AddKey(current, convert);
      89             :   }
      90     9058855 : }
      91             : 
      92         389 : void KeyAccumulator::AddKeys(Handle<JSObject> array_like,
      93             :                              AddKeyConversion convert) {
      94             :   DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements());
      95         389 :   ElementsAccessor* accessor = array_like->GetElementsAccessor();
      96         389 :   accessor->AddElementsToKeyAccumulator(array_like, this, convert);
      97         389 : }
      98             : 
      99        2538 : MaybeHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator,
     100             :                                         Handle<JSProxy> owner,
     101             :                                         Handle<FixedArray> keys,
     102             :                                         PropertyFilter filter) {
     103        1580 :   if (filter == ALL_PROPERTIES) {
     104             :     // Nothing to do.
     105         622 :     return keys;
     106             :   }
     107             :   Isolate* isolate = accumulator->isolate();
     108             :   int store_position = 0;
     109        6796 :   for (int i = 0; i < keys->length(); ++i) {
     110             :     Handle<Name> key(Name::cast(keys->get(i)), isolate);
     111        2512 :     if (key->FilterKey(filter)) continue;  // Skip this key.
     112        2395 :     if (filter & ONLY_ENUMERABLE) {
     113             :       PropertyDescriptor desc;
     114             :       Maybe<bool> found =
     115        1275 :           JSProxy::GetOwnPropertyDescriptor(isolate, owner, key, &desc);
     116        1275 :       MAYBE_RETURN(found, MaybeHandle<FixedArray>());
     117        1392 :       if (!found.FromJust()) continue;
     118        1086 :       if (!desc.enumerable()) {
     119          72 :         accumulator->AddShadowingKey(key);
     120          72 :         continue;
     121             :       }
     122             :     }
     123             :     // Keep this key.
     124        2134 :     if (store_position != i) {
     125         144 :       keys->set(store_position, *key);
     126             :     }
     127        2134 :     store_position++;
     128             :   }
     129        1035 :   if (store_position == 0) return isolate->factory()->empty_fixed_array();
     130         737 :   keys->Shrink(store_position);
     131         737 :   return keys;
     132             : }
     133             : 
     134             : // Returns "nothing" in case of exception, "true" on success.
     135      923535 : Maybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy,
     136             :                                                Handle<FixedArray> keys) {
     137             :   // Postpone the enumerable check for for-in to the ForInFilter step.
     138      923535 :   if (!is_for_in_) {
     139        3160 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     140             :         isolate_, keys, FilterProxyKeys(this, proxy, keys, filter_),
     141             :         Nothing<bool>());
     142        1508 :     if (mode_ == KeyCollectionMode::kOwnOnly) {
     143             :       // If we collect only the keys from a JSProxy do not sort or deduplicate.
     144        1496 :       keys_ = keys;
     145             :       return Just(true);
     146             :     }
     147             :   }
     148      921967 :   AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
     149             :   return Just(true);
     150             : }
     151             : 
     152     5435201 : Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
     153             :                                         Handle<JSReceiver> object) {
     154             :   // Proxies have no hidden prototype and we should not trigger the
     155             :   // [[GetPrototypeOf]] trap on the last iteration when using
     156             :   // AdvanceFollowingProxies.
     157     5638963 :   if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) {
     158        1883 :     MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)),
     159             :                  Nothing<bool>());
     160             :     return Just(true);
     161             :   }
     162             : 
     163     5433318 :   PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly
     164             :                                           ? PrototypeIterator::END_AT_NON_HIDDEN
     165     5433318 :                                           : PrototypeIterator::END_AT_NULL;
     166    20143815 :   for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end);
     167    14710497 :        !iter.IsAtEnd();) {
     168             :     // Start the shadow checks only after the first prototype has added
     169             :     // shadowing keys.
     170     9279244 :     if (HasShadowingKeys()) skip_shadow_check_ = false;
     171             :     Handle<JSReceiver> current =
     172             :         PrototypeIterator::GetCurrent<JSReceiver>(iter);
     173             :     Maybe<bool> result = Just(false);  // Dummy initialization.
     174     9279244 :     if (current->IsJSProxy()) {
     175      922021 :       result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current));
     176             :     } else {
     177             :       DCHECK(current->IsJSObject());
     178     8357223 :       result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current));
     179             :     }
     180     9279244 :     MAYBE_RETURN(result, Nothing<bool>());
     181     9279157 :     if (!result.FromJust()) break;  // |false| means "stop iterating".
     182             :     // Iterate through proxies but ignore access checks for the ALL_CAN_READ
     183             :     // case on API objects for OWN_ONLY keys handled in CollectOwnKeys.
     184     9279116 :     if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
     185             :       return Nothing<bool>();
     186             :     }
     187     9283204 :     if (!last_non_empty_prototype_.is_null() &&
     188             :         *last_non_empty_prototype_ == *current) {
     189             :       break;
     190             :     }
     191             :   }
     192             :   return Just(true);
     193             : }
     194             : 
     195           0 : bool KeyAccumulator::HasShadowingKeys() { return !shadowing_keys_.is_null(); }
     196             : 
     197    46791419 : bool KeyAccumulator::IsShadowed(Handle<Object> key) {
     198    46791419 :   if (!HasShadowingKeys() || skip_shadow_check_) return false;
     199       21566 :   return shadowing_keys_->Has(isolate_, key);
     200             : }
     201             : 
     202       61744 : void KeyAccumulator::AddShadowingKey(Object* key) {
     203      123488 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     204      118594 :   AddShadowingKey(handle(key, isolate_));
     205             : }
     206       59369 : void KeyAccumulator::AddShadowingKey(Handle<Object> key) {
     207      118738 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     208       59297 :   if (shadowing_keys_.is_null()) {
     209        1758 :     shadowing_keys_ = ObjectHashSet::New(isolate_, 16);
     210             :   }
     211       59297 :   shadowing_keys_ = ObjectHashSet::Add(shadowing_keys_, key);
     212             : }
     213             : 
     214             : namespace {
     215             : 
     216        6938 : void TrySettingEmptyEnumCache(JSReceiver* object) {
     217             :   Map* map = object->map();
     218             :   DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
     219        6938 :   if (!map->OnlyHasSimpleProperties()) return;
     220        5657 :   if (map->IsJSProxyMap()) return;
     221        5657 :   if (map->NumberOfEnumerableProperties() > 0) return;
     222             :   DCHECK(object->IsJSObject());
     223             :   map->SetEnumLength(0);
     224             : }
     225             : 
     226      109126 : bool CheckAndInitalizeEmptyEnumCache(JSReceiver* object) {
     227      109126 :   if (object->map()->EnumLength() == kInvalidEnumCacheSentinel) {
     228        6938 :     TrySettingEmptyEnumCache(object);
     229             :   }
     230      109126 :   if (object->map()->EnumLength() != 0) return false;
     231             :   DCHECK(object->IsJSObject());
     232      107119 :   return !JSObject::cast(object)->HasEnumerableElements();
     233             : }
     234             : }  // namespace
     235             : 
     236     1390006 : void FastKeyAccumulator::Prepare() {
     237             :   DisallowHeapAllocation no_gc;
     238             :   // Directly go for the fast path for OWN_ONLY keys.
     239     2780012 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     240             :   // Fully walk the prototype chain and find the last prototype with keys.
     241       59739 :   is_receiver_simple_enum_ = false;
     242       59739 :   has_empty_prototype_ = true;
     243             :   JSReceiver* last_prototype = nullptr;
     244      228604 :   for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
     245      109126 :        iter.Advance()) {
     246      109126 :     JSReceiver* current = iter.GetCurrent<JSReceiver>();
     247      109126 :     bool has_no_properties = CheckAndInitalizeEmptyEnumCache(current);
     248      109126 :     if (has_no_properties) continue;
     249             :     last_prototype = current;
     250        2053 :     has_empty_prototype_ = false;
     251             :   }
     252       59739 :   if (has_empty_prototype_) {
     253             :     is_receiver_simple_enum_ =
     254      102910 :         receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
     255      102910 :         !JSObject::cast(*receiver_)->HasEnumerableElements();
     256        1963 :   } else if (last_prototype != nullptr) {
     257        3926 :     last_non_empty_prototype_ = handle(last_prototype, isolate_);
     258             :   }
     259             : }
     260             : 
     261             : namespace {
     262             : 
     263     9026210 : Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
     264             :                                       Handle<FixedArray> array, int length) {
     265             :   DCHECK_LE(length, array->length());
     266     9026210 :   if (array->length() == length) return array;
     267     2086612 :   return isolate->factory()->CopyFixedArrayUpTo(array, length);
     268             : }
     269             : 
     270             : // Initializes and directly returns the enume cache. Users of this function
     271             : // have to make sure to never directly leak the enum cache.
     272     9215329 : Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
     273             :                                            Handle<JSObject> object) {
     274             :   Handle<Map> map(object->map(), isolate);
     275             :   Handle<FixedArray> keys(map->instance_descriptors()->GetEnumCache()->keys(),
     276             :                           isolate);
     277             : 
     278             :   // Check if the {map} has a valid enum length, which implies that it
     279             :   // must have a valid enum cache as well.
     280             :   int enum_length = map->EnumLength();
     281     9215329 :   if (enum_length != kInvalidEnumCacheSentinel) {
     282             :     DCHECK(map->OnlyHasSimpleProperties());
     283             :     DCHECK_LE(enum_length, keys->length());
     284             :     DCHECK_EQ(enum_length, map->NumberOfEnumerableProperties());
     285     8994963 :     isolate->counters()->enum_cache_hits()->Increment();
     286     8994963 :     return ReduceFixedArrayTo(isolate, keys, enum_length);
     287             :   }
     288             : 
     289             :   // Determine the actual number of enumerable properties of the {map}.
     290      220366 :   enum_length = map->NumberOfEnumerableProperties();
     291             : 
     292             :   // Check if there's already a shared enum cache on the {map}s
     293             :   // DescriptorArray with sufficient number of entries.
     294      220366 :   if (enum_length <= keys->length()) {
     295       31247 :     if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
     296       31247 :     isolate->counters()->enum_cache_hits()->Increment();
     297       31247 :     return ReduceFixedArrayTo(isolate, keys, enum_length);
     298             :   }
     299             : 
     300             :   Handle<DescriptorArray> descriptors =
     301             :       Handle<DescriptorArray>(map->instance_descriptors(), isolate);
     302      189119 :   isolate->counters()->enum_cache_misses()->Increment();
     303             :   int nod = map->NumberOfOwnDescriptors();
     304             : 
     305             :   // Create the keys array.
     306             :   int index = 0;
     307             :   bool fields_only = true;
     308      189119 :   keys = isolate->factory()->NewFixedArray(enum_length);
     309      996357 :   for (int i = 0; i < nod; i++) {
     310             :     DisallowHeapAllocation no_gc;
     311      807238 :     PropertyDetails details = descriptors->GetDetails(i);
     312      807238 :     if (details.IsDontEnum()) continue;
     313             :     Object* key = descriptors->GetKey(i);
     314      805704 :     if (key->IsSymbol()) continue;
     315      805611 :     keys->set(index, key);
     316      805611 :     if (details.location() != kField) fields_only = false;
     317      805611 :     index++;
     318             :   }
     319             :   DCHECK_EQ(index, keys->length());
     320             : 
     321             :   // Optionally also create the indices array.
     322             :   Handle<FixedArray> indices = isolate->factory()->empty_fixed_array();
     323      189119 :   if (fields_only) {
     324       52901 :     indices = isolate->factory()->NewFixedArray(enum_length);
     325             :     index = 0;
     326      349546 :     for (int i = 0; i < nod; i++) {
     327             :       DisallowHeapAllocation no_gc;
     328      296645 :       PropertyDetails details = descriptors->GetDetails(i);
     329      297960 :       if (details.IsDontEnum()) continue;
     330             :       Object* key = descriptors->GetKey(i);
     331      295405 :       if (key->IsSymbol()) continue;
     332             :       DCHECK_EQ(kData, details.kind());
     333             :       DCHECK_EQ(kField, details.location());
     334      295330 :       FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
     335      295330 :       indices->set(index, Smi::FromInt(field_index.GetLoadByFieldIndex()));
     336      295330 :       index++;
     337             :     }
     338             :     DCHECK_EQ(index, indices->length());
     339             :   }
     340             : 
     341      189119 :   DescriptorArray::SetEnumCache(descriptors, isolate, keys, indices);
     342      189119 :   if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
     343             : 
     344      189119 :   return keys;
     345             : }
     346             : 
     347             : template <bool fast_properties>
     348     1008267 : MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate,
     349             :                                                Handle<JSObject> object,
     350             :                                                GetKeysConversion convert) {
     351             :   Handle<FixedArray> keys;
     352     1008267 :   ElementsAccessor* accessor = object->GetElementsAccessor();
     353             :   if (fast_properties) {
     354     1001628 :     keys = GetFastEnumPropertyKeys(isolate, object);
     355             :   } else {
     356             :     // TODO(cbruni): preallocate big enough array to also hold elements.
     357        6639 :     keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate, object);
     358             :   }
     359             :   MaybeHandle<FixedArray> result =
     360     1008267 :       accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE);
     361             : 
     362     1008267 :   if (FLAG_trace_for_in_enumerate) {
     363           0 :     PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n",
     364           0 :            keys->length(), result.ToHandleChecked()->length() - keys->length());
     365             :   }
     366     1008267 :   return result;
     367             : }
     368             : 
     369             : bool OnlyHasSimpleProperties(Map* map) {
     370             :   return map->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER;
     371             : }
     372             : 
     373             : }  // namespace
     374             : 
     375     1387138 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(
     376             :     GetKeysConversion keys_conversion) {
     377     1387138 :   if (filter_ == ENUMERABLE_STRINGS) {
     378             :     Handle<FixedArray> keys;
     379     2408990 :     if (GetKeysFast(keys_conversion).ToHandle(&keys)) {
     380     1181681 :       return keys;
     381             :     }
     382       22814 :     if (isolate_->has_pending_exception()) return MaybeHandle<FixedArray>();
     383             :   }
     384             : 
     385      205457 :   return GetKeysSlow(keys_conversion);
     386             : }
     387             : 
     388     1204495 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
     389             :     GetKeysConversion keys_conversion) {
     390     1204495 :   bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly;
     391             :   Map* map = receiver_->map();
     392     2407027 :   if (!own_only || !OnlyHasSimpleProperties(map)) {
     393       22814 :     return MaybeHandle<FixedArray>();
     394             :   }
     395             : 
     396             :   // From this point on we are certain to only collect own keys.
     397             :   DCHECK(receiver_->IsJSObject());
     398             :   Handle<JSObject> object = Handle<JSObject>::cast(receiver_);
     399             : 
     400             :   // Do not try to use the enum-cache for dict-mode objects.
     401     1181681 :   if (map->is_dictionary_map()) {
     402        6639 :     return GetOwnKeysWithElements<false>(isolate_, object, keys_conversion);
     403             :   }
     404             :   int enum_length = receiver_->map()->EnumLength();
     405     1175042 :   if (enum_length == kInvalidEnumCacheSentinel) {
     406             :     Handle<FixedArray> keys;
     407             :     // Try initializing the enum cache and return own properties.
     408      350802 :     if (GetOwnKeysWithUninitializedEnumCache().ToHandle(&keys)) {
     409      173414 :       if (FLAG_trace_for_in_enumerate) {
     410             :         PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n",
     411           0 :                keys->length());
     412             :       }
     413             :       is_receiver_simple_enum_ =
     414      173414 :           object->map()->EnumLength() != kInvalidEnumCacheSentinel;
     415      173414 :       return keys;
     416             :     }
     417             :   }
     418             :   // The properties-only case failed because there were probably elements on the
     419             :   // receiver.
     420     1001628 :   return GetOwnKeysWithElements<true>(isolate_, object, keys_conversion);
     421             : }
     422             : 
     423             : MaybeHandle<FixedArray>
     424      175401 : FastKeyAccumulator::GetOwnKeysWithUninitializedEnumCache() {
     425             :   Handle<JSObject> object = Handle<JSObject>::cast(receiver_);
     426             :   // Uninitalized enum cache
     427             :   Map* map = object->map();
     428      175401 :   if (object->elements()->length() != 0) {
     429             :     // Assume that there are elements.
     430        1987 :     return MaybeHandle<FixedArray>();
     431             :   }
     432             :   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
     433      173414 :   if (number_of_own_descriptors == 0) {
     434             :     map->SetEnumLength(0);
     435       36316 :     return isolate_->factory()->empty_fixed_array();
     436             :   }
     437             :   // We have no elements but possibly enumerable property keys, hence we can
     438             :   // directly initialize the enum cache.
     439      155256 :   Handle<FixedArray> keys = GetFastEnumPropertyKeys(isolate_, object);
     440      155256 :   if (is_for_in_) return keys;
     441             :   // Do not leak the enum cache as it might end up as an elements backing store.
     442      147449 :   return isolate_->factory()->CopyFixedArray(keys);
     443             : }
     444             : 
     445      205457 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
     446             :     GetKeysConversion keys_conversion) {
     447      205457 :   KeyAccumulator accumulator(isolate_, mode_, filter_);
     448      205457 :   accumulator.set_is_for_in(is_for_in_);
     449             :   accumulator.set_last_non_empty_prototype(last_non_empty_prototype_);
     450             : 
     451      205457 :   MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_),
     452             :                MaybeHandle<FixedArray>());
     453      204974 :   return accumulator.GetKeys(keys_conversion);
     454             : }
     455             : 
     456             : namespace {
     457             : 
     458             : enum IndexedOrNamed { kIndexed, kNamed };
     459             : 
     460          48 : void FilterForEnumerableProperties(Handle<JSReceiver> receiver,
     461             :                                    Handle<JSObject> object,
     462             :                                    Handle<InterceptorInfo> interceptor,
     463         156 :                                    KeyAccumulator* accumulator,
     464             :                                    Handle<JSObject> result,
     465             :                                    IndexedOrNamed type) {
     466             :   DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements());
     467          48 :   ElementsAccessor* accessor = result->GetElementsAccessor();
     468             : 
     469          96 :   uint32_t length = accessor->GetCapacity(*result, result->elements());
     470         258 :   for (uint32_t i = 0; i < length; i++) {
     471         474 :     if (!accessor->HasEntry(*result, i)) continue;
     472             : 
     473             :     // args are invalid after args.Call(), create a new one in every iteration.
     474             :     PropertyCallbackArguments args(accumulator->isolate(), interceptor->data(),
     475             :                                    *receiver, *object, Object::DONT_THROW);
     476             : 
     477         156 :     Handle<Object> element = accessor->Get(result, i);
     478             :     Handle<Object> attributes;
     479         156 :     if (type == kIndexed) {
     480             :       uint32_t number;
     481          84 :       CHECK(element->ToUint32(&number));
     482             :       attributes = args.Call(
     483             :           v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query()),
     484         168 :           number);
     485             :     } else {
     486          72 :       CHECK(element->IsName());
     487             :       attributes = args.Call(v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
     488             :                                  interceptor->query()),
     489          72 :                              Handle<Name>::cast(element));
     490             :     }
     491             : 
     492         156 :     if (!attributes.is_null()) {
     493             :       int32_t value;
     494         144 :       CHECK(attributes->ToInt32(&value));
     495         144 :       if ((value & DONT_ENUM) == 0) {
     496          48 :         accumulator->AddKey(element, DO_NOT_CONVERT);
     497             :       }
     498             :     }
     499             :   }
     500          48 : }
     501             : 
     502             : // Returns |true| on success, |nothing| on exception.
     503         527 : Maybe<bool> CollectInterceptorKeysInternal(Handle<JSReceiver> receiver,
     504             :                                            Handle<JSObject> object,
     505             :                                            Handle<InterceptorInfo> interceptor,
     506         964 :                                            KeyAccumulator* accumulator,
     507             :                                            IndexedOrNamed type) {
     508         527 :   Isolate* isolate = accumulator->isolate();
     509             :   PropertyCallbackArguments enum_args(isolate, interceptor->data(), *receiver,
     510             :                                       *object, Object::DONT_THROW);
     511             : 
     512             :   Handle<JSObject> result;
     513         527 :   if (!interceptor->enumerator()->IsUndefined(isolate)) {
     514         527 :     if (type == kIndexed) {
     515             :       v8::IndexedPropertyEnumeratorCallback enum_fun =
     516             :           v8::ToCData<v8::IndexedPropertyEnumeratorCallback>(
     517             :               interceptor->enumerator());
     518             :       const char* log_tag = "interceptor-indexed-enum";
     519         267 :       LOG(isolate, ApiObjectAccess(log_tag, *object));
     520         267 :       result = enum_args.Call(enum_fun);
     521             :     } else {
     522             :       DCHECK_EQ(type, kNamed);
     523             :       v8::GenericNamedPropertyEnumeratorCallback enum_fun =
     524             :           v8::ToCData<v8::GenericNamedPropertyEnumeratorCallback>(
     525             :               interceptor->enumerator());
     526             :       const char* log_tag = "interceptor-named-enum";
     527         260 :       LOG(isolate, ApiObjectAccess(log_tag, *object));
     528         260 :       result = enum_args.Call(enum_fun);
     529             :     }
     530             :   }
     531         527 :   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
     532         503 :   if (result.is_null()) return Just(true);
     533             : 
     534         532 :   if ((accumulator->filter() & ONLY_ENUMERABLE) &&
     535             :       !interceptor->query()->IsUndefined(isolate)) {
     536             :     FilterForEnumerableProperties(receiver, object, interceptor, accumulator,
     537          48 :                                   result, type);
     538             :   } else {
     539             :     accumulator->AddKeys(
     540         389 :         result, type == kIndexed ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
     541             :   }
     542             :   return Just(true);
     543             : }
     544             : 
     545    16634768 : Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver,
     546             :                                    Handle<JSObject> object,
     547    16635247 :                                    KeyAccumulator* accumulator,
     548             :                                    IndexedOrNamed type) {
     549             :   Isolate* isolate = accumulator->isolate();
     550    16634768 :   if (type == kIndexed) {
     551     8277546 :     if (!object->HasIndexedInterceptor()) return Just(true);
     552             :   } else {
     553     8357222 :     if (!object->HasNamedInterceptor()) return Just(true);
     554             :   }
     555             :   Handle<InterceptorInfo> interceptor(type == kIndexed
     556             :                                           ? object->GetIndexedInterceptor()
     557             :                                           : object->GetNamedInterceptor(),
     558         958 :                                       isolate);
     559         479 :   if ((accumulator->filter() & ONLY_ALL_CAN_READ) &&
     560             :       !interceptor->all_can_read()) {
     561             :     return Just(true);
     562             :   }
     563             :   return CollectInterceptorKeysInternal(receiver, object, interceptor,
     564         479 :                                         accumulator, type);
     565             : }
     566             : 
     567             : }  // namespace
     568             : 
     569     8364517 : Maybe<bool> KeyAccumulator::CollectOwnElementIndices(
     570             :     Handle<JSReceiver> receiver, Handle<JSObject> object) {
     571     8364517 :   if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true);
     572             : 
     573     8277546 :   ElementsAccessor* accessor = object->GetElementsAccessor();
     574     8277546 :   accessor->CollectElementIndices(object, this);
     575             : 
     576     8277546 :   return CollectInterceptorKeys(receiver, object, this, kIndexed);
     577             : }
     578             : 
     579             : namespace {
     580             : 
     581             : template <bool skip_symbols>
     582      189168 : int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
     583      880873 :                                     KeyAccumulator* keys,
     584             :                                     Handle<DescriptorArray> descs,
     585             :                                     int start_index, int limit) {
     586             :   int first_skipped = -1;
     587             :   PropertyFilter filter = keys->filter();
     588             :   KeyCollectionMode mode = keys->mode();
     589      734121 :   for (int i = start_index; i < limit; i++) {
     590             :     bool is_shadowing_key = false;
     591      734121 :     PropertyDetails details = descs->GetDetails(i);
     592             : 
     593      734121 :     if ((details.attributes() & filter) != 0) {
     594         150 :       if (mode == KeyCollectionMode::kIncludePrototypes) {
     595             :         is_shadowing_key = true;
     596             :       } else {
     597             :         continue;
     598             :       }
     599             :     }
     600             : 
     601      734115 :     if (filter & ONLY_ALL_CAN_READ) {
     602          12 :       if (details.kind() != kAccessor) continue;
     603             :       Object* accessors = descs->GetValue(i);
     604           6 :       if (!accessors->IsAccessorInfo()) continue;
     605           6 :       if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
     606             :     }
     607             : 
     608             :     Name* key = descs->GetKey(i);
     609      734109 :     if (skip_symbols == key->IsSymbol()) {
     610       42404 :       if (first_skipped == -1) first_skipped = i;
     611             :       continue;
     612             :     }
     613      691705 :     if (key->FilterKey(keys->filter())) continue;
     614             : 
     615      467454 :     if (is_shadowing_key) {
     616         144 :       keys->AddShadowingKey(key);
     617             :     } else {
     618      467310 :       keys->AddKey(key, DO_NOT_CONVERT);
     619             :     }
     620             :   }
     621      189168 :   return first_skipped;
     622             : }
     623             : 
     624             : template <class T>
     625       87474 : Handle<FixedArray> GetOwnEnumPropertyDictionaryKeys(Isolate* isolate,
     626             :                                                     KeyCollectionMode mode,
     627             :                                                     KeyAccumulator* accumulator,
     628             :                                                     Handle<JSObject> object,
     629             :                                                     T* raw_dictionary) {
     630             :   Handle<T> dictionary(raw_dictionary, isolate);
     631       87474 :   int length = dictionary->NumberOfEnumerableProperties();
     632       87474 :   if (length == 0) {
     633             :     return isolate->factory()->empty_fixed_array();
     634             :   }
     635       86823 :   Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
     636       86823 :   T::CopyEnumKeysTo(dictionary, storage, mode, accumulator);
     637       86823 :   return storage;
     638             : }
     639             : }  // namespace
     640             : 
     641     8357222 : Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver,
     642             :                                                     Handle<JSObject> object) {
     643     8357222 :   if (filter_ == ENUMERABLE_STRINGS) {
     644             :     Handle<FixedArray> enum_keys;
     645     8136888 :     if (object->HasFastProperties()) {
     646     8056193 :       enum_keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, object);
     647             :       // If the number of properties equals the length of enumerable properties
     648             :       // we do not have to filter out non-enumerable ones
     649             :       Map* map = object->map();
     650             :       int nof_descriptors = map->NumberOfOwnDescriptors();
     651     8056193 :       if (enum_keys->length() != nof_descriptors) {
     652             :         Handle<DescriptorArray> descs =
     653        4274 :             Handle<DescriptorArray>(map->instance_descriptors(), isolate_);
     654       55432 :         for (int i = 0; i < nof_descriptors; i++) {
     655       51158 :           PropertyDetails details = descs->GetDetails(i);
     656       54586 :           if (!details.IsDontEnum()) continue;
     657             :           Object* key = descs->GetKey(i);
     658       47730 :           this->AddShadowingKey(key);
     659             :         }
     660             :       }
     661       80695 :     } else if (object->IsJSGlobalObject()) {
     662             :       enum_keys = GetOwnEnumPropertyDictionaryKeys(
     663             :           isolate_, mode_, this, object,
     664       18309 :           JSGlobalObject::cast(*object)->global_dictionary());
     665             :     } else {
     666             :       enum_keys = GetOwnEnumPropertyDictionaryKeys(
     667       62386 :           isolate_, mode_, this, object, object->property_dictionary());
     668             :     }
     669     8136888 :     AddKeys(enum_keys, DO_NOT_CONVERT);
     670             :   } else {
     671      220334 :     if (object->HasFastProperties()) {
     672             :       int limit = object->map()->NumberOfOwnDescriptors();
     673             :       Handle<DescriptorArray> descs(object->map()->instance_descriptors(),
     674      180679 :                                     isolate_);
     675             :       // First collect the strings,
     676             :       int first_symbol =
     677      180679 :           CollectOwnPropertyNamesInternal<true>(object, this, descs, 0, limit);
     678             :       // then the symbols.
     679      180679 :       if (first_symbol != -1) {
     680             :         CollectOwnPropertyNamesInternal<false>(object, this, descs,
     681        8489 :                                                first_symbol, limit);
     682             :       }
     683       39655 :     } else if (object->IsJSGlobalObject()) {
     684             :       GlobalDictionary::CollectKeysTo(
     685             :           handle(JSGlobalObject::cast(*object)->global_dictionary(), isolate_),
     686       77558 :           this);
     687             :     } else {
     688             :       NameDictionary::CollectKeysTo(
     689        1752 :           handle(object->property_dictionary(), isolate_), this);
     690             :     }
     691             :   }
     692             :   // Add the property keys from the interceptor.
     693     8357222 :   return CollectInterceptorKeys(receiver, object, this, kNamed);
     694             : }
     695             : 
     696          24 : Maybe<bool> KeyAccumulator::CollectAccessCheckInterceptorKeys(
     697             :     Handle<AccessCheckInfo> access_check_info, Handle<JSReceiver> receiver,
     698             :     Handle<JSObject> object) {
     699          48 :   MAYBE_RETURN((CollectInterceptorKeysInternal(
     700             :                    receiver, object,
     701             :                    handle(InterceptorInfo::cast(
     702             :                               access_check_info->indexed_interceptor()),
     703             :                           isolate_),
     704             :                    this, kIndexed)),
     705             :                Nothing<bool>());
     706          48 :   MAYBE_RETURN(
     707             :       (CollectInterceptorKeysInternal(
     708             :           receiver, object,
     709             :           handle(InterceptorInfo::cast(access_check_info->named_interceptor()),
     710             :                  isolate_),
     711             :           this, kNamed)),
     712             :       Nothing<bool>());
     713             :   return Just(true);
     714             : }
     715             : 
     716             : // Returns |true| on success, |false| if prototype walking should be stopped,
     717             : // |nothing| if an exception was thrown.
     718     8357223 : Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
     719             :                                            Handle<JSObject> object) {
     720             :   // Check access rights if required.
     721     8357327 :   if (object->IsAccessCheckNeeded() &&
     722         208 :       !isolate_->MayAccess(handle(isolate_->context()), object)) {
     723             :     // The cross-origin spec says that [[Enumerate]] shall return an empty
     724             :     // iterator when it doesn't have access...
     725          75 :     if (mode_ == KeyCollectionMode::kIncludePrototypes) {
     726             :       return Just(false);
     727             :     }
     728             :     // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
     729             :     DCHECK_EQ(KeyCollectionMode::kOwnOnly, mode_);
     730             :     Handle<AccessCheckInfo> access_check_info;
     731             :     {
     732             :       DisallowHeapAllocation no_gc;
     733          58 :       AccessCheckInfo* maybe_info = AccessCheckInfo::Get(isolate_, object);
     734          58 :       if (maybe_info) access_check_info = handle(maybe_info, isolate_);
     735             :     }
     736             :     // We always have both kinds of interceptors or none.
     737         104 :     if (!access_check_info.is_null() &&
     738             :         access_check_info->named_interceptor()) {
     739          24 :       MAYBE_RETURN(CollectAccessCheckInterceptorKeys(access_check_info,
     740             :                                                      receiver, object),
     741             :                    Nothing<bool>());
     742             :       return Just(false);
     743             :     }
     744          34 :     filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ);
     745             :   }
     746     8357182 :   MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>());
     747     8357170 :   MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>());
     748             :   return Just(true);
     749             : }
     750             : 
     751             : // static
     752     8065224 : Handle<FixedArray> KeyAccumulator::GetOwnEnumPropertyKeys(
     753             :     Isolate* isolate, Handle<JSObject> object) {
     754     8065224 :   if (object->HasFastProperties()) {
     755     8058445 :     return GetFastEnumPropertyKeys(isolate, object);
     756        6779 :   } else if (object->IsJSGlobalObject()) {
     757             :     return GetOwnEnumPropertyDictionaryKeys(
     758             :         isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
     759          20 :         JSGlobalObject::cast(*object)->global_dictionary());
     760             :   } else {
     761             :     return GetOwnEnumPropertyDictionaryKeys(
     762             :         isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
     763        6759 :         object->property_dictionary());
     764             :   }
     765             : }
     766             : 
     767             : namespace {
     768             : 
     769             : struct NameComparator {
     770             :   bool operator()(uint32_t hash1, uint32_t hash2, const Handle<Name>& key1,
     771             :                   const Handle<Name>& key2) const {
     772         622 :     return Name::Equals(key1, key2);
     773             :   }
     774             : };
     775             : 
     776             : }  // namespace
     777             : 
     778             : // ES6 9.5.12
     779             : // Returns |true| on success, |nothing| in case of exception.
     780      923904 : Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver,
     781             :                                                   Handle<JSProxy> proxy) {
     782     1847981 :   STACK_CHECK(isolate_, Nothing<bool>());
     783             :   // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
     784             :   Handle<Object> handler(proxy->handler(), isolate_);
     785             :   // 2. If handler is null, throw a TypeError exception.
     786             :   // 3. Assert: Type(handler) is Object.
     787      923904 :   if (proxy->IsRevoked()) {
     788             :     isolate_->Throw(*isolate_->factory()->NewTypeError(
     789          54 :         MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string()));
     790             :     return Nothing<bool>();
     791             :   }
     792             :   // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
     793      923886 :   Handle<JSReceiver> target(proxy->target(), isolate_);
     794             :   // 5. Let trap be ? GetMethod(handler, "ownKeys").
     795             :   Handle<Object> trap;
     796     2771658 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     797             :       isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
     798             :                                         isolate_->factory()->ownKeys_string()),
     799             :       Nothing<bool>());
     800             :   // 6. If trap is undefined, then
     801     1847700 :   if (trap->IsUndefined(isolate_)) {
     802             :     // 6a. Return target.[[OwnPropertyKeys]]().
     803      922578 :     return CollectOwnJSProxyTargetKeys(proxy, target);
     804             :   }
     805             :   // 7. Let trapResultArray be Call(trap, handler, «target»).
     806             :   Handle<Object> trap_result_array;
     807             :   Handle<Object> args[] = {target};
     808        2544 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     809             :       isolate_, trap_result_array,
     810             :       Execution::Call(isolate_, trap, handler, arraysize(args), args),
     811             :       Nothing<bool>());
     812             :   // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
     813             :   //    «String, Symbol»).
     814             :   Handle<FixedArray> trap_result;
     815        2202 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     816             :       isolate_, trap_result,
     817             :       Object::CreateListFromArrayLike(isolate_, trap_result_array,
     818             :                                       ElementTypes::kStringAndSymbol),
     819             :       Nothing<bool>());
     820             :   // 9. Let extensibleTarget be ? IsExtensible(target).
     821         984 :   Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
     822         984 :   MAYBE_RETURN(maybe_extensible, Nothing<bool>());
     823             :   bool extensible_target = maybe_extensible.FromJust();
     824             :   // 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
     825             :   Handle<FixedArray> target_keys;
     826        1968 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, target_keys,
     827             :                                    JSReceiver::OwnPropertyKeys(target),
     828             :                                    Nothing<bool>());
     829             :   // 11. (Assert)
     830             :   // 12. Let targetConfigurableKeys be an empty List.
     831             :   // To save memory, we're re-using target_keys and will modify it in-place.
     832             :   Handle<FixedArray> target_configurable_keys = target_keys;
     833             :   // 13. Let targetNonconfigurableKeys be an empty List.
     834             :   Handle<FixedArray> target_nonconfigurable_keys =
     835         984 :       isolate_->factory()->NewFixedArray(target_keys->length());
     836             :   int nonconfigurable_keys_length = 0;
     837             :   // 14. Repeat, for each element key of targetKeys:
     838        3452 :   for (int i = 0; i < target_keys->length(); ++i) {
     839             :     // 14a. Let desc be ? target.[[GetOwnProperty]](key).
     840             :     PropertyDescriptor desc;
     841             :     Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
     842        1484 :         isolate_, target, handle(target_keys->get(i), isolate_), &desc);
     843         742 :     MAYBE_RETURN(found, Nothing<bool>());
     844             :     // 14b. If desc is not undefined and desc.[[Configurable]] is false, then
     845        1484 :     if (found.FromJust() && !desc.configurable()) {
     846             :       // 14b i. Append key as an element of targetNonconfigurableKeys.
     847             :       target_nonconfigurable_keys->set(nonconfigurable_keys_length,
     848         273 :                                        target_keys->get(i));
     849         273 :       nonconfigurable_keys_length++;
     850             :       // The key was moved, null it out in the original list.
     851             :       target_keys->set(i, Smi::kZero);
     852             :     } else {
     853             :       // 14c. Else,
     854             :       // 14c i. Append key as an element of targetConfigurableKeys.
     855             :       // (No-op, just keep it in |target_keys|.)
     856             :     }
     857             :   }
     858             :   // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty,
     859             :   //     then:
     860         984 :   if (extensible_target && nonconfigurable_keys_length == 0) {
     861             :     // 15a. Return trapResult.
     862         811 :     return AddKeysFromJSProxy(proxy, trap_result);
     863             :   }
     864             :   // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
     865         346 :   Zone set_zone(isolate_->allocator(), ZONE_NAME);
     866             :   ZoneAllocationPolicy alloc(&set_zone);
     867             :   const int kPresent = 1;
     868             :   const int kGone = 0;
     869             :   base::TemplateHashMapImpl<Handle<Name>, int, NameComparator,
     870             :                             ZoneAllocationPolicy>
     871             :       unchecked_result_keys(ZoneHashMap::kDefaultHashMapCapacity,
     872             :                             NameComparator(), alloc);
     873             :   int unchecked_result_keys_size = 0;
     874        1578 :   for (int i = 0; i < trap_result->length(); ++i) {
     875         616 :     Handle<Name> key(Name::cast(trap_result->get(i)), isolate_);
     876             :     auto entry = unchecked_result_keys.LookupOrInsert(key, key->Hash(), alloc);
     877         616 :     if (entry->value != kPresent) {
     878         499 :       entry->value = kPresent;
     879         499 :       unchecked_result_keys_size++;
     880             :     }
     881             :   }
     882             :   // 17. Repeat, for each key that is an element of targetNonconfigurableKeys:
     883         264 :   for (int i = 0; i < nonconfigurable_keys_length; ++i) {
     884             :     Object* raw_key = target_nonconfigurable_keys->get(i);
     885         273 :     Handle<Name> key(Name::cast(raw_key), isolate_);
     886             :     // 17a. If key is not an element of uncheckedResultKeys, throw a
     887             :     //      TypeError exception.
     888             :     auto found = unchecked_result_keys.Lookup(key, key->Hash());
     889         273 :     if (found == nullptr || found->value == kGone) {
     890             :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     891          18 :           MessageTemplate::kProxyOwnKeysMissing, key));
     892           9 :       return Nothing<bool>();
     893             :     }
     894             :     // 17b. Remove key from uncheckedResultKeys.
     895         264 :     found->value = kGone;
     896         264 :     unchecked_result_keys_size--;
     897             :   }
     898             :   // 18. If extensibleTarget is true, return trapResult.
     899         164 :   if (extensible_target) {
     900          64 :     return AddKeysFromJSProxy(proxy, trap_result);
     901             :   }
     902             :   // 19. Repeat, for each key that is an element of targetConfigurableKeys:
     903         680 :   for (int i = 0; i < target_configurable_keys->length(); ++i) {
     904             :     Object* raw_key = target_configurable_keys->get(i);
     905         480 :     if (raw_key->IsSmi()) continue;  // Zapped entry, was nonconfigurable.
     906         118 :     Handle<Name> key(Name::cast(raw_key), isolate_);
     907             :     // 19a. If key is not an element of uncheckedResultKeys, throw a
     908             :     //      TypeError exception.
     909             :     auto found = unchecked_result_keys.Lookup(key, key->Hash());
     910         118 :     if (found == nullptr || found->value == kGone) {
     911             :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     912          18 :           MessageTemplate::kProxyOwnKeysMissing, key));
     913           9 :       return Nothing<bool>();
     914             :     }
     915             :     // 19b. Remove key from uncheckedResultKeys.
     916         109 :     found->value = kGone;
     917         109 :     unchecked_result_keys_size--;
     918             :   }
     919             :   // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
     920          91 :   if (unchecked_result_keys_size != 0) {
     921             :     DCHECK_GT(unchecked_result_keys_size, 0);
     922             :     isolate_->Throw(*isolate_->factory()->NewTypeError(
     923          18 :         MessageTemplate::kProxyOwnKeysNonExtensible));
     924             :     return Nothing<bool>();
     925             :   }
     926             :   // 21. Return trapResult.
     927          82 :   return AddKeysFromJSProxy(proxy, trap_result);
     928             : }
     929             : 
     930      922578 : Maybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys(
     931             :     Handle<JSProxy> proxy, Handle<JSReceiver> target) {
     932             :   // TODO(cbruni): avoid creating another KeyAccumulator
     933             :   Handle<FixedArray> keys;
     934     1845156 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     935             :       isolate_, keys,
     936             :       KeyAccumulator::GetKeys(target, KeyCollectionMode::kOwnOnly, filter_,
     937             :                               GetKeysConversion::kConvertToString, is_for_in_),
     938             :       Nothing<bool>());
     939      922578 :   Maybe<bool> result = AddKeysFromJSProxy(proxy, keys);
     940      922578 :   return result;
     941             : }
     942             : 
     943             : }  // namespace internal
     944             : }  // namespace v8

Generated by: LCOV version 1.10