LCOV - code coverage report
Current view: top level - src - keys.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 385 394 97.7 %
Date: 2019-04-17 Functions: 39 41 95.1 %

          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-inl.h"
       9             : #include "src/field-index-inl.h"
      10             : #include "src/handles-inl.h"
      11             : #include "src/heap/factory.h"
      12             : #include "src/identity-map.h"
      13             : #include "src/isolate-inl.h"
      14             : #include "src/objects-inl.h"
      15             : #include "src/objects/api-callbacks.h"
      16             : #include "src/objects/hash-table-inl.h"
      17             : #include "src/objects/module-inl.h"
      18             : #include "src/objects/ordered-hash-table-inl.h"
      19             : #include "src/property-descriptor.h"
      20             : #include "src/prototype.h"
      21             : 
      22             : namespace v8 {
      23             : namespace internal {
      24             : 
      25             : namespace {
      26             : 
      27             : static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
      28             :   int len = array->length();
      29             :   for (int i = 0; i < len; i++) {
      30             :     Object e = array->get(i);
      31             :     if (!(e->IsName() || e->IsNumber())) return false;
      32             :   }
      33             :   return true;
      34             : }
      35             : 
      36             : }  // namespace
      37             : 
      38             : // static
      39     1417486 : MaybeHandle<FixedArray> KeyAccumulator::GetKeys(
      40             :     Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter,
      41             :     GetKeysConversion keys_conversion, bool is_for_in, bool skip_indices) {
      42             :   Isolate* isolate = object->GetIsolate();
      43             :   FastKeyAccumulator accumulator(isolate, object, mode, filter, is_for_in,
      44             :                                  skip_indices);
      45     1417486 :   return accumulator.GetKeys(keys_conversion);
      46             : }
      47             : 
      48     1262214 : Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
      49     1262214 :   if (keys_.is_null()) {
      50     1010940 :     return isolate_->factory()->empty_fixed_array();
      51             :   }
      52      495254 :   if (mode_ == KeyCollectionMode::kOwnOnly &&
      53      243980 :       keys_->map() == ReadOnlyRoots(isolate_).fixed_array_map()) {
      54             :     return Handle<FixedArray>::cast(keys_);
      55             :   }
      56             :   USE(ContainsOnlyValidKeys);
      57             :   Handle<FixedArray> result =
      58      249610 :       OrderedHashSet::ConvertToKeysArray(isolate(), keys(), convert);
      59             :   DCHECK(ContainsOnlyValidKeys(result));
      60      249610 :   return result;
      61             : }
      62             : 
      63           0 : Handle<OrderedHashSet> KeyAccumulator::keys() {
      64           0 :   return Handle<OrderedHashSet>::cast(keys_);
      65             : }
      66             : 
      67     3950836 : void KeyAccumulator::AddKey(Object key, AddKeyConversion convert) {
      68     7901672 :   AddKey(handle(key, isolate_), convert);
      69     3950836 : }
      70             : 
      71    10052528 : void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
      72    10052528 :   if (filter_ == PRIVATE_NAMES_ONLY) {
      73        9473 :     if (!key->IsSymbol()) return;
      74          95 :     if (!Symbol::cast(*key)->is_private_name()) return;
      75    10052433 :   } else if (key->IsSymbol()) {
      76       45717 :     if (filter_ & SKIP_SYMBOLS) return;
      77             : 
      78       45660 :     if (Symbol::cast(*key)->is_private()) return;
      79    10006716 :   } else if (filter_ & SKIP_STRINGS) {
      80             :     return;
      81             :   }
      82             : 
      83    10052465 :   if (IsShadowed(key)) return;
      84    10043150 :   if (keys_.is_null()) {
      85      249643 :     keys_ = OrderedHashSet::Allocate(isolate_, 16);
      86             :   }
      87             :   uint32_t index;
      88    20089202 :   if (convert == CONVERT_TO_ARRAY_INDEX && key->IsString() &&
      89    10044307 :       Handle<String>::cast(key)->AsArrayIndex(&index)) {
      90         374 :     key = isolate_->factory()->NewNumberFromUint(index);
      91             :   }
      92    10043150 :   Handle<OrderedHashSet> new_set = OrderedHashSet::Add(isolate(), keys(), key);
      93    10043150 :   if (*new_set != *keys_) {
      94             :     // The keys_ Set is converted directly to a FixedArray in GetKeys which can
      95             :     // be left-trimmer. Hence the previous Set should not keep a pointer to the
      96             :     // new one.
      97      195672 :     keys_->set(OrderedHashSet::NextTableIndex(), Smi::kZero);
      98      195672 :     keys_ = new_set;
      99             :   }
     100             : }
     101             : 
     102      994189 : void KeyAccumulator::AddKeys(Handle<FixedArray> array,
     103             :                              AddKeyConversion convert) {
     104             :   int add_length = array->length();
     105     6159055 :   for (int i = 0; i < add_length; i++) {
     106     2582433 :     Handle<Object> current(array->get(i), isolate_);
     107     2582433 :     AddKey(current, convert);
     108             :   }
     109      994189 : }
     110             : 
     111         309 : void KeyAccumulator::AddKeys(Handle<JSObject> array_like,
     112             :                              AddKeyConversion convert) {
     113             :   DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements());
     114         309 :   ElementsAccessor* accessor = array_like->GetElementsAccessor();
     115         309 :   accessor->AddElementsToKeyAccumulator(array_like, this, convert);
     116         309 : }
     117             : 
     118        1783 : MaybeHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator,
     119             :                                         Handle<JSProxy> owner,
     120             :                                         Handle<FixedArray> keys,
     121             :                                         PropertyFilter filter) {
     122        1783 :   if (filter == ALL_PROPERTIES) {
     123             :     // Nothing to do.
     124         621 :     return keys;
     125             :   }
     126             :   Isolate* isolate = accumulator->isolate();
     127             :   int store_position = 0;
     128        7944 :   for (int i = 0; i < keys->length(); ++i) {
     129             :     Handle<Name> key(Name::cast(keys->get(i)), isolate);
     130        3463 :     if (key->FilterKey(filter)) continue;  // Skip this key.
     131        3199 :     if (filter & ONLY_ENUMERABLE) {
     132             :       PropertyDescriptor desc;
     133             :       Maybe<bool> found =
     134        1714 :           JSProxy::GetOwnPropertyDescriptor(isolate, owner, key, &desc);
     135        1714 :       MAYBE_RETURN(found, MaybeHandle<FixedArray>());
     136        1885 :       if (!found.FromJust()) continue;
     137        1525 :       if (!desc.enumerable()) {
     138         126 :         accumulator->AddShadowingKey(key);
     139         126 :         continue;
     140             :       }
     141             :     }
     142             :     // Keep this key.
     143        2884 :     if (store_position != i) {
     144         180 :       keys->set(store_position, *key);
     145             :     }
     146        2884 :     store_position++;
     147             :   }
     148        1090 :   return FixedArray::ShrinkOrEmpty(isolate, keys, store_position);
     149             : }
     150             : 
     151             : // Returns "nothing" in case of exception, "true" on success.
     152      923869 : Maybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy,
     153             :                                                Handle<FixedArray> keys) {
     154             :   // Postpone the enumerable check for for-in to the ForInFilter step.
     155      923869 :   if (!is_for_in_) {
     156        3566 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     157             :         isolate_, keys, FilterProxyKeys(this, proxy, keys, filter_),
     158             :         Nothing<bool>());
     159        1711 :     if (mode_ == KeyCollectionMode::kOwnOnly) {
     160             :       // If we collect only the keys from a JSProxy do not sort or deduplicate.
     161        1664 :       keys_ = keys;
     162             :       return Just(true);
     163             :     }
     164             :   }
     165      922133 :   AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
     166             :   return Just(true);
     167             : }
     168             : 
     169     1279564 : Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
     170             :                                         Handle<JSReceiver> object) {
     171             :   // Proxies have no hidden prototype and we should not trigger the
     172             :   // [[GetPrototypeOf]] trap on the last iteration when using
     173             :   // AdvanceFollowingProxies.
     174     2551250 :   if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) {
     175       49682 :     MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)),
     176             :                  Nothing<bool>());
     177             :     return Just(true);
     178             :   }
     179             : 
     180     1254723 :   PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly
     181             :                                           ? PrototypeIterator::END_AT_NON_HIDDEN
     182     1254723 :                                           : PrototypeIterator::END_AT_NULL;
     183     4751017 :   for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end);
     184             :        !iter.IsAtEnd();) {
     185             :     // Start the shadow checks only after the first prototype has added
     186             :     // shadowing keys.
     187     2243178 :     if (HasShadowingKeys()) skip_shadow_check_ = false;
     188             :     Handle<JSReceiver> current =
     189             :         PrototypeIterator::GetCurrent<JSReceiver>(iter);
     190             :     Maybe<bool> result = Just(false);  // Dummy initialization.
     191     2243178 :     if (current->IsJSProxy()) {
     192      922196 :       result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current));
     193             :     } else {
     194             :       DCHECK(current->IsJSObject());
     195     1320982 :       result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current));
     196             :     }
     197     2243178 :     MAYBE_RETURN(result, Nothing<bool>());
     198     2243022 :     if (!result.FromJust()) break;  // |false| means "stop iterating".
     199             :     // Iterate through proxies but ignore access checks for the ALL_CAN_READ
     200             :     // case on API objects for OWN_ONLY keys handled in CollectOwnKeys.
     201     2242985 :     if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
     202             :       return Nothing<bool>();
     203             :     }
     204     2246015 :     if (!last_non_empty_prototype_.is_null() &&
     205             :         *last_non_empty_prototype_ == *current) {
     206             :       break;
     207             :     }
     208             :   }
     209             :   return Just(true);
     210             : }
     211             : 
     212           0 : bool KeyAccumulator::HasShadowingKeys() { return !shadowing_keys_.is_null(); }
     213             : 
     214    10052465 : bool KeyAccumulator::IsShadowed(Handle<Object> key) {
     215    10052465 :   if (!HasShadowingKeys() || skip_shadow_check_) return false;
     216       19854 :   return shadowing_keys_->Has(isolate_, key);
     217             : }
     218             : 
     219      111070 : void KeyAccumulator::AddShadowingKey(Object key) {
     220      111070 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     221      214856 :   AddShadowingKey(handle(key, isolate_));
     222             : }
     223      107554 : void KeyAccumulator::AddShadowingKey(Handle<Object> key) {
     224      107554 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     225      107428 :   if (shadowing_keys_.is_null()) {
     226        6619 :     shadowing_keys_ = ObjectHashSet::New(isolate_, 16);
     227             :   }
     228      107428 :   shadowing_keys_ = ObjectHashSet::Add(isolate(), shadowing_keys_, key);
     229             : }
     230             : 
     231             : namespace {
     232             : 
     233        4663 : void TrySettingEmptyEnumCache(JSReceiver object) {
     234        4663 :   Map map = object->map();
     235             :   DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
     236        5675 :   if (!map->OnlyHasSimpleProperties()) return;
     237        3993 :   if (map->IsJSProxyMap()) return;
     238        3993 :   if (map->NumberOfEnumerableProperties() > 0) return;
     239             :   DCHECK(object->IsJSObject());
     240        3651 :   map->SetEnumLength(0);
     241             : }
     242             : 
     243      102016 : bool CheckAndInitalizeEmptyEnumCache(JSReceiver object) {
     244      102016 :   if (object->map()->EnumLength() == kInvalidEnumCacheSentinel) {
     245        4663 :     TrySettingEmptyEnumCache(object);
     246             :   }
     247      102016 :   if (object->map()->EnumLength() != 0) return false;
     248             :   DCHECK(object->IsJSObject());
     249      100536 :   return !JSObject::cast(object)->HasEnumerableElements();
     250             : }
     251             : }  // namespace
     252             : 
     253     1471929 : void FastKeyAccumulator::Prepare() {
     254             :   DisallowHeapAllocation no_gc;
     255             :   // Directly go for the fast path for OWN_ONLY keys.
     256     1471929 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     257             :   // Fully walk the prototype chain and find the last prototype with keys.
     258       54443 :   is_receiver_simple_enum_ = false;
     259       54443 :   has_empty_prototype_ = true;
     260             :   JSReceiver last_prototype;
     261      312918 :   for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
     262      102016 :        iter.Advance()) {
     263             :     JSReceiver current = iter.GetCurrent<JSReceiver>();
     264      102016 :     bool has_no_properties = CheckAndInitalizeEmptyEnumCache(current);
     265      102016 :     if (has_no_properties) continue;
     266             :     last_prototype = current;
     267        1525 :     has_empty_prototype_ = false;
     268             :   }
     269       54443 :   if (has_empty_prototype_) {
     270             :     is_receiver_simple_enum_ =
     271       97285 :         receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
     272       97285 :         !JSObject::cast(*receiver_)->HasEnumerableElements();
     273        1440 :   } else if (!last_prototype.is_null()) {
     274        2880 :     last_non_empty_prototype_ = handle(last_prototype, isolate_);
     275             :   }
     276             : }
     277             : 
     278             : namespace {
     279             : 
     280      175708 : Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
     281             :                                       Handle<FixedArray> array, int length) {
     282             :   DCHECK_LE(length, array->length());
     283      175708 :   if (array->length() == length) return array;
     284         284 :   return isolate->factory()->CopyFixedArrayUpTo(array, length);
     285             : }
     286             : 
     287             : // Initializes and directly returns the enume cache. Users of this function
     288             : // have to make sure to never directly leak the enum cache.
     289      223558 : Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
     290             :                                            Handle<JSObject> object) {
     291             :   Handle<Map> map(object->map(), isolate);
     292             :   Handle<FixedArray> keys(map->instance_descriptors()->enum_cache()->keys(),
     293             :                           isolate);
     294             : 
     295             :   // Check if the {map} has a valid enum length, which implies that it
     296             :   // must have a valid enum cache as well.
     297             :   int enum_length = map->EnumLength();
     298      223558 :   if (enum_length != kInvalidEnumCacheSentinel) {
     299             :     DCHECK(map->OnlyHasSimpleProperties());
     300             :     DCHECK_LE(enum_length, keys->length());
     301             :     DCHECK_EQ(enum_length, map->NumberOfEnumerableProperties());
     302      149229 :     isolate->counters()->enum_cache_hits()->Increment();
     303      149229 :     return ReduceFixedArrayTo(isolate, keys, enum_length);
     304             :   }
     305             : 
     306             :   // Determine the actual number of enumerable properties of the {map}.
     307       74329 :   enum_length = map->NumberOfEnumerableProperties();
     308             : 
     309             :   // Check if there's already a shared enum cache on the {map}s
     310             :   // DescriptorArray with sufficient number of entries.
     311       74329 :   if (enum_length <= keys->length()) {
     312       32544 :     if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
     313       26479 :     isolate->counters()->enum_cache_hits()->Increment();
     314       26479 :     return ReduceFixedArrayTo(isolate, keys, enum_length);
     315             :   }
     316             : 
     317             :   Handle<DescriptorArray> descriptors =
     318             :       Handle<DescriptorArray>(map->instance_descriptors(), isolate);
     319       47850 :   isolate->counters()->enum_cache_misses()->Increment();
     320             :   int nod = map->NumberOfOwnDescriptors();
     321             : 
     322             :   // Create the keys array.
     323             :   int index = 0;
     324             :   bool fields_only = true;
     325       47850 :   keys = isolate->factory()->NewFixedArray(enum_length);
     326      674846 :   for (int i = 0; i < nod; i++) {
     327             :     DisallowHeapAllocation no_gc;
     328      313498 :     PropertyDetails details = descriptors->GetDetails(i);
     329      313498 :     if (details.IsDontEnum()) continue;
     330             :     Object key = descriptors->GetKey(i);
     331      302798 :     if (key->IsSymbol()) continue;
     332      302669 :     keys->set(index, key);
     333      302669 :     if (details.location() != kField) fields_only = false;
     334      302669 :     index++;
     335             :   }
     336             :   DCHECK_EQ(index, keys->length());
     337             : 
     338             :   // Optionally also create the indices array.
     339             :   Handle<FixedArray> indices = isolate->factory()->empty_fixed_array();
     340       47850 :   if (fields_only) {
     341       47712 :     indices = isolate->factory()->NewFixedArray(enum_length);
     342             :     index = 0;
     343      673508 :     for (int i = 0; i < nod; i++) {
     344             :       DisallowHeapAllocation no_gc;
     345      312898 :       PropertyDetails details = descriptors->GetDetails(i);
     346      323569 :       if (details.IsDontEnum()) continue;
     347             :       Object key = descriptors->GetKey(i);
     348      302356 :       if (key->IsSymbol()) continue;
     349             :       DCHECK_EQ(kData, details.kind());
     350             :       DCHECK_EQ(kField, details.location());
     351      302227 :       FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
     352             :       indices->set(index, Smi::FromInt(field_index.GetLoadByFieldIndex()));
     353      302227 :       index++;
     354             :     }
     355             :     DCHECK_EQ(index, indices->length());
     356             :   }
     357             : 
     358             :   DescriptorArray::InitializeOrChangeEnumCache(descriptors, isolate, keys,
     359       47850 :                                                indices);
     360       95602 :   if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
     361             : 
     362       47850 :   return keys;
     363             : }
     364             : 
     365             : template <bool fast_properties>
     366      142825 : MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate,
     367             :                                                Handle<JSObject> object,
     368             :                                                GetKeysConversion convert,
     369             :                                                bool skip_indices) {
     370             :   Handle<FixedArray> keys;
     371      142825 :   ElementsAccessor* accessor = object->GetElementsAccessor();
     372             :   if (fast_properties) {
     373      136440 :     keys = GetFastEnumPropertyKeys(isolate, object);
     374             :   } else {
     375             :     // TODO(cbruni): preallocate big enough array to also hold elements.
     376        6385 :     keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate, object);
     377             :   }
     378             : 
     379             :   MaybeHandle<FixedArray> result;
     380      142825 :   if (skip_indices) {
     381             :     result = keys;
     382             :   } else {
     383      142712 :     result =
     384             :         accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE);
     385             :   }
     386             : 
     387      142825 :   if (FLAG_trace_for_in_enumerate) {
     388           0 :     PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n",
     389             :            keys->length(), result.ToHandleChecked()->length() - keys->length());
     390             :   }
     391      142825 :   return result;
     392             : }
     393             : 
     394             : }  // namespace
     395             : 
     396     1469080 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(
     397             :     GetKeysConversion keys_conversion) {
     398     1469080 :   if (filter_ == ENUMERABLE_STRINGS) {
     399             :     Handle<FixedArray> keys;
     400      473436 :     if (GetKeysFast(keys_conversion).ToHandle(&keys)) {
     401      196134 :       return keys;
     402             :     }
     403       81168 :     if (isolate_->has_pending_exception()) return MaybeHandle<FixedArray>();
     404             :   }
     405             : 
     406     1272946 :   return GetKeysSlow(keys_conversion);
     407             : }
     408             : 
     409      236718 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
     410             :     GetKeysConversion keys_conversion) {
     411      236718 :   bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly;
     412             :   Map map = receiver_->map();
     413      471996 :   if (!own_only || map->IsCustomElementsReceiverMap()) {
     414       40584 :     return MaybeHandle<FixedArray>();
     415             :   }
     416             : 
     417             :   // From this point on we are certain to only collect own keys.
     418             :   DCHECK(receiver_->IsJSObject());
     419             :   Handle<JSObject> object = Handle<JSObject>::cast(receiver_);
     420             : 
     421             :   // Do not try to use the enum-cache for dict-mode objects.
     422      196134 :   if (map->is_dictionary_map()) {
     423             :     return GetOwnKeysWithElements<false>(isolate_, object, keys_conversion,
     424        6385 :                                          skip_indices_);
     425             :   }
     426             :   int enum_length = receiver_->map()->EnumLength();
     427      189749 :   if (enum_length == kInvalidEnumCacheSentinel) {
     428             :     Handle<FixedArray> keys;
     429             :     // Try initializing the enum cache and return own properties.
     430      111244 :     if (GetOwnKeysWithUninitializedEnumCache().ToHandle(&keys)) {
     431       53309 :       if (FLAG_trace_for_in_enumerate) {
     432             :         PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n",
     433           0 :                keys->length());
     434             :       }
     435             :       is_receiver_simple_enum_ =
     436       53309 :           object->map()->EnumLength() != kInvalidEnumCacheSentinel;
     437       53309 :       return keys;
     438             :     }
     439             :   }
     440             :   // The properties-only case failed because there were probably elements on the
     441             :   // receiver.
     442             :   return GetOwnKeysWithElements<true>(isolate_, object, keys_conversion,
     443      136440 :                                       skip_indices_);
     444             : }
     445             : 
     446             : MaybeHandle<FixedArray>
     447       55622 : FastKeyAccumulator::GetOwnKeysWithUninitializedEnumCache() {
     448             :   Handle<JSObject> object = Handle<JSObject>::cast(receiver_);
     449             :   // Uninitalized enum cache
     450       55622 :   Map map = object->map();
     451      113582 :   if (object->elements() != ReadOnlyRoots(isolate_).empty_fixed_array() &&
     452             :       object->elements() !=
     453             :           ReadOnlyRoots(isolate_).empty_slow_element_dictionary()) {
     454             :     // Assume that there are elements.
     455        2313 :     return MaybeHandle<FixedArray>();
     456             :   }
     457             :   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
     458       53309 :   if (number_of_own_descriptors == 0) {
     459        4234 :     map->SetEnumLength(0);
     460        8468 :     return isolate_->factory()->empty_fixed_array();
     461             :   }
     462             :   // We have no elements but possibly enumerable property keys, hence we can
     463             :   // directly initialize the enum cache.
     464       49075 :   Handle<FixedArray> keys = GetFastEnumPropertyKeys(isolate_, object);
     465       49075 :   if (is_for_in_) return keys;
     466             :   // Do not leak the enum cache as it might end up as an elements backing store.
     467       44460 :   return isolate_->factory()->CopyFixedArray(keys);
     468             : }
     469             : 
     470     1272946 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
     471             :     GetKeysConversion keys_conversion) {
     472     1272946 :   KeyAccumulator accumulator(isolate_, mode_, filter_);
     473     1272946 :   accumulator.set_is_for_in(is_for_in_);
     474     1272946 :   accumulator.set_skip_indices(skip_indices_);
     475             :   accumulator.set_last_non_empty_prototype(last_non_empty_prototype_);
     476             : 
     477     2545892 :   MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_),
     478             :                MaybeHandle<FixedArray>());
     479     1249629 :   return accumulator.GetKeys(keys_conversion);
     480             : }
     481             : 
     482             : namespace {
     483             : 
     484             : enum IndexedOrNamed { kIndexed, kNamed };
     485             : 
     486          60 : void FilterForEnumerableProperties(Handle<JSReceiver> receiver,
     487             :                                    Handle<JSObject> object,
     488             :                                    Handle<InterceptorInfo> interceptor,
     489             :                                    KeyAccumulator* accumulator,
     490             :                                    Handle<JSObject> result,
     491             :                                    IndexedOrNamed type) {
     492             :   DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements());
     493          60 :   ElementsAccessor* accessor = result->GetElementsAccessor();
     494             : 
     495         120 :   uint32_t length = accessor->GetCapacity(*result, result->elements());
     496         504 :   for (uint32_t i = 0; i < length; i++) {
     497         510 :     if (!accessor->HasEntry(*result, i)) continue;
     498             : 
     499             :     // args are invalid after args.Call(), create a new one in every iteration.
     500             :     PropertyCallbackArguments args(accumulator->isolate(), interceptor->data(),
     501         312 :                                    *receiver, *object, Just(kDontThrow));
     502             : 
     503         156 :     Handle<Object> element = accessor->Get(result, i);
     504             :     Handle<Object> attributes;
     505         156 :     if (type == kIndexed) {
     506             :       uint32_t number;
     507          84 :       CHECK(element->ToUint32(&number));
     508          84 :       attributes = args.CallIndexedQuery(interceptor, number);
     509             :     } else {
     510          72 :       CHECK(element->IsName());
     511             :       attributes =
     512          72 :           args.CallNamedQuery(interceptor, Handle<Name>::cast(element));
     513             :     }
     514             : 
     515         156 :     if (!attributes.is_null()) {
     516             :       int32_t value;
     517         144 :       CHECK(attributes->ToInt32(&value));
     518         144 :       if ((value & DONT_ENUM) == 0) {
     519          48 :         accumulator->AddKey(element, DO_NOT_CONVERT);
     520             :       }
     521             :     }
     522             :   }
     523          60 : }
     524             : 
     525             : // Returns |true| on success, |nothing| on exception.
     526         475 : Maybe<bool> CollectInterceptorKeysInternal(Handle<JSReceiver> receiver,
     527             :                                            Handle<JSObject> object,
     528             :                                            Handle<InterceptorInfo> interceptor,
     529             :                                            KeyAccumulator* accumulator,
     530             :                                            IndexedOrNamed type) {
     531             :   Isolate* isolate = accumulator->isolate();
     532             :   PropertyCallbackArguments enum_args(isolate, interceptor->data(), *receiver,
     533         950 :                                       *object, Just(kDontThrow));
     534             : 
     535             :   Handle<JSObject> result;
     536         475 :   if (!interceptor->enumerator()->IsUndefined(isolate)) {
     537         475 :     if (type == kIndexed) {
     538         235 :       result = enum_args.CallIndexedEnumerator(interceptor);
     539             :     } else {
     540             :       DCHECK_EQ(type, kNamed);
     541         240 :       result = enum_args.CallNamedEnumerator(interceptor);
     542             :     }
     543             :   }
     544         475 :   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
     545         445 :   if (result.is_null()) return Just(true);
     546             : 
     547         488 :   if ((accumulator->filter() & ONLY_ENUMERABLE) &&
     548             :       !interceptor->query()->IsUndefined(isolate)) {
     549             :     FilterForEnumerableProperties(receiver, object, interceptor, accumulator,
     550          60 :                                   result, type);
     551             :   } else {
     552         309 :     accumulator->AddKeys(
     553         309 :         result, type == kIndexed ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
     554             :   }
     555             :   return Just(true);
     556             : }
     557             : 
     558     2452417 : Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver,
     559             :                                    Handle<JSObject> object,
     560             :                                    KeyAccumulator* accumulator,
     561             :                                    IndexedOrNamed type) {
     562             :   Isolate* isolate = accumulator->isolate();
     563     2452417 :   if (type == kIndexed) {
     564     1228628 :     if (!object->HasIndexedInterceptor()) return Just(true);
     565             :   } else {
     566     1223789 :     if (!object->HasNamedInterceptor()) return Just(true);
     567             :   }
     568             :   Handle<InterceptorInfo> interceptor(type == kIndexed
     569         865 :                                           ? object->GetIndexedInterceptor()
     570         655 :                                           : object->GetNamedInterceptor(),
     571        1090 :                                       isolate);
     572         435 :   if ((accumulator->filter() & ONLY_ALL_CAN_READ) &&
     573             :       !interceptor->all_can_read()) {
     574             :     return Just(true);
     575             :   }
     576             :   return CollectInterceptorKeysInternal(receiver, object, interceptor,
     577         435 :                                         accumulator, type);
     578             : }
     579             : 
     580             : }  // namespace
     581             : 
     582     1229216 : Maybe<bool> KeyAccumulator::CollectOwnElementIndices(
     583             :     Handle<JSReceiver> receiver, Handle<JSObject> object) {
     584     1229216 :   if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true);
     585             : 
     586     1228628 :   ElementsAccessor* accessor = object->GetElementsAccessor();
     587     1228628 :   accessor->CollectElementIndices(object, this);
     588             : 
     589     1228628 :   return CollectInterceptorKeys(receiver, object, this, kIndexed);
     590             : }
     591             : 
     592             : namespace {
     593             : 
     594             : template <bool skip_symbols>
     595     1226729 : int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
     596             :                                     KeyAccumulator* keys,
     597             :                                     Handle<DescriptorArray> descs,
     598             :                                     int start_index, int limit) {
     599             :   int first_skipped = -1;
     600             :   PropertyFilter filter = keys->filter();
     601             :   KeyCollectionMode mode = keys->mode();
     602     4041935 :   for (int i = start_index; i < limit; i++) {
     603             :     bool is_shadowing_key = false;
     604     1407603 :     PropertyDetails details = descs->GetDetails(i);
     605             : 
     606     1407603 :     if ((details.attributes() & filter) != 0) {
     607          12 :       if (mode == KeyCollectionMode::kIncludePrototypes) {
     608             :         is_shadowing_key = true;
     609             :       } else {
     610      376802 :         continue;
     611             :       }
     612             :     }
     613             : 
     614     1407591 :     if (filter & ONLY_ALL_CAN_READ) {
     615          12 :       if (details.kind() != kAccessor) continue;
     616             :       Object accessors = descs->GetStrongValue(i);
     617           6 :       if (!accessors->IsAccessorInfo()) continue;
     618           6 :       if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
     619             :     }
     620             : 
     621     1407585 :     Name key = descs->GetKey(i);
     622     1407585 :     if (skip_symbols == key->IsSymbol()) {
     623      363910 :       if (first_skipped == -1) first_skipped = i;
     624             :       continue;
     625             :     }
     626     1043675 :     if (key->FilterKey(keys->filter())) continue;
     627             : 
     628     1030801 :     if (is_shadowing_key) {
     629           0 :       keys->AddShadowingKey(key);
     630             :     } else {
     631     1030801 :       keys->AddKey(key, DO_NOT_CONVERT);
     632             :     }
     633             :   }
     634     1226729 :   return first_skipped;
     635             : }
     636             : 
     637             : template <class T>
     638       43191 : Handle<FixedArray> GetOwnEnumPropertyDictionaryKeys(Isolate* isolate,
     639             :                                                     KeyCollectionMode mode,
     640             :                                                     KeyAccumulator* accumulator,
     641             :                                                     Handle<JSObject> object,
     642             :                                                     T raw_dictionary) {
     643             :   Handle<T> dictionary(raw_dictionary, isolate);
     644       43191 :   if (dictionary->NumberOfElements() == 0) {
     645             :     return isolate->factory()->empty_fixed_array();
     646             :   }
     647       42917 :   int length = dictionary->NumberOfEnumerableProperties();
     648       42917 :   Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
     649       42917 :   T::CopyEnumKeysTo(isolate, dictionary, storage, mode, accumulator);
     650       42917 :   return storage;
     651             : }
     652             : }  // namespace
     653             : 
     654     1223843 : Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver,
     655             :                                                     Handle<JSObject> object) {
     656     1223843 :   if (filter_ == ENUMERABLE_STRINGS) {
     657             :     Handle<FixedArray> enum_keys;
     658       72110 :     if (object->HasFastProperties()) {
     659       35512 :       enum_keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, object);
     660             :       // If the number of properties equals the length of enumerable properties
     661             :       // we do not have to filter out non-enumerable ones
     662             :       Map map = object->map();
     663             :       int nof_descriptors = map->NumberOfOwnDescriptors();
     664       35512 :       if (enum_keys->length() != nof_descriptors) {
     665             :         Handle<DescriptorArray> descs =
     666        8972 :             Handle<DescriptorArray>(map->instance_descriptors(), isolate_);
     667      230270 :         for (int i = 0; i < nof_descriptors; i++) {
     668      110649 :           PropertyDetails details = descs->GetDetails(i);
     669      114208 :           if (!details.IsDontEnum()) continue;
     670      107090 :           Object key = descs->GetKey(i);
     671      107090 :           this->AddShadowingKey(key);
     672             :         }
     673             :       }
     674       36598 :     } else if (object->IsJSGlobalObject()) {
     675             :       enum_keys = GetOwnEnumPropertyDictionaryKeys(
     676             :           isolate_, mode_, this, object,
     677       36269 :           JSGlobalObject::cast(*object)->global_dictionary());
     678             :     } else {
     679             :       enum_keys = GetOwnEnumPropertyDictionaryKeys(
     680         329 :           isolate_, mode_, this, object, object->property_dictionary());
     681             :     }
     682       72110 :     if (object->IsJSModuleNamespace()) {
     683             :       // Simulate [[GetOwnProperty]] for establishing enumerability, which
     684             :       // throws for uninitialized exports.
     685         504 :       for (int i = 0, n = enum_keys->length(); i < n; ++i) {
     686         243 :         Handle<String> key(String::cast(enum_keys->get(i)), isolate_);
     687         243 :         if (Handle<JSModuleNamespace>::cast(object)
     688         486 :                 ->GetExport(isolate(), key)
     689             :                 .is_null()) {
     690          54 :           return Nothing<bool>();
     691             :         }
     692             :       }
     693             :     }
     694       72056 :     AddKeys(enum_keys, DO_NOT_CONVERT);
     695             :   } else {
     696     1151733 :     if (object->HasFastProperties()) {
     697             :       int limit = object->map()->NumberOfOwnDescriptors();
     698             :       Handle<DescriptorArray> descs(object->map()->instance_descriptors(),
     699     1128292 :                                     isolate_);
     700             :       // First collect the strings,
     701             :       int first_symbol =
     702     1128292 :           CollectOwnPropertyNamesInternal<true>(object, this, descs, 0, limit);
     703             :       // then the symbols.
     704     1128292 :       if (first_symbol != -1) {
     705             :         CollectOwnPropertyNamesInternal<false>(object, this, descs,
     706       19228 :                                                first_symbol, limit);
     707             :       }
     708       23441 :     } else if (object->IsJSGlobalObject()) {
     709       22673 :       GlobalDictionary::CollectKeysTo(
     710             :           handle(JSGlobalObject::cast(*object)->global_dictionary(), isolate_),
     711       22673 :           this);
     712             :     } else {
     713        1536 :       NameDictionary::CollectKeysTo(
     714        1536 :           handle(object->property_dictionary(), isolate_), this);
     715             :     }
     716             :   }
     717             :   // Add the property keys from the interceptor.
     718     1223789 :   return CollectInterceptorKeys(receiver, object, this, kNamed);
     719             : }
     720             : 
     721       97141 : void KeyAccumulator::CollectPrivateNames(Handle<JSReceiver> receiver,
     722             :                                          Handle<JSObject> object) {
     723       97141 :   if (object->HasFastProperties()) {
     724             :     int limit = object->map()->NumberOfOwnDescriptors();
     725             :     Handle<DescriptorArray> descs(object->map()->instance_descriptors(),
     726       79209 :                                   isolate_);
     727       79209 :     CollectOwnPropertyNamesInternal<false>(object, this, descs, 0, limit);
     728       17932 :   } else if (object->IsJSGlobalObject()) {
     729       17893 :     GlobalDictionary::CollectKeysTo(
     730             :         handle(JSGlobalObject::cast(*object)->global_dictionary(), isolate_),
     731       17893 :         this);
     732             :   } else {
     733          78 :     NameDictionary::CollectKeysTo(
     734          78 :         handle(object->property_dictionary(), isolate_), this);
     735             :   }
     736       97141 : }
     737             : 
     738          20 : Maybe<bool> KeyAccumulator::CollectAccessCheckInterceptorKeys(
     739             :     Handle<AccessCheckInfo> access_check_info, Handle<JSReceiver> receiver,
     740             :     Handle<JSObject> object) {
     741          20 :   if (!skip_indices_) {
     742          60 :     MAYBE_RETURN((CollectInterceptorKeysInternal(
     743             :                      receiver, object,
     744             :                      handle(InterceptorInfo::cast(
     745             :                                 access_check_info->indexed_interceptor()),
     746             :                             isolate_),
     747             :                      this, kIndexed)),
     748             :                  Nothing<bool>());
     749             :   }
     750          60 :   MAYBE_RETURN(
     751             :       (CollectInterceptorKeysInternal(
     752             :           receiver, object,
     753             :           handle(InterceptorInfo::cast(access_check_info->named_interceptor()),
     754             :                  isolate_),
     755             :           this, kNamed)),
     756             :       Nothing<bool>());
     757             :   return Just(true);
     758             : }
     759             : 
     760             : // Returns |true| on success, |false| if prototype walking should be stopped,
     761             : // |nothing| if an exception was thrown.
     762     1320982 : Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
     763             :                                            Handle<JSObject> object) {
     764             :   // Check access rights if required.
     765     1321076 :   if (object->IsAccessCheckNeeded() &&
     766         188 :       !isolate_->MayAccess(handle(isolate_->context(), isolate_), object)) {
     767             :     // The cross-origin spec says that [[Enumerate]] shall return an empty
     768             :     // iterator when it doesn't have access...
     769          69 :     if (mode_ == KeyCollectionMode::kIncludePrototypes) {
     770             :       return Just(false);
     771             :     }
     772             :     // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
     773             :     DCHECK_EQ(KeyCollectionMode::kOwnOnly, mode_);
     774             :     Handle<AccessCheckInfo> access_check_info;
     775             :     {
     776             :       DisallowHeapAllocation no_gc;
     777          52 :       AccessCheckInfo maybe_info = AccessCheckInfo::Get(isolate_, object);
     778          52 :       if (!maybe_info.is_null()) {
     779          42 :         access_check_info = handle(maybe_info, isolate_);
     780             :       }
     781             :     }
     782             :     // We always have both kinds of interceptors or none.
     783          94 :     if (!access_check_info.is_null() &&
     784             :         access_check_info->named_interceptor() != Object()) {
     785          40 :       MAYBE_RETURN(CollectAccessCheckInterceptorKeys(access_check_info,
     786             :                                                      receiver, object),
     787             :                    Nothing<bool>());
     788             :       return Just(false);
     789             :     }
     790          32 :     filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ);
     791             :   }
     792     1320945 :   if (filter_ & PRIVATE_NAMES_ONLY) {
     793       97141 :     CollectPrivateNames(receiver, object);
     794             :     return Just(true);
     795             :   }
     796             : 
     797     2447608 :   MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>());
     798     2447584 :   MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>());
     799             :   return Just(true);
     800             : }
     801             : 
     802             : // static
     803       44636 : Handle<FixedArray> KeyAccumulator::GetOwnEnumPropertyKeys(
     804             :     Isolate* isolate, Handle<JSObject> object) {
     805       44636 :   if (object->HasFastProperties()) {
     806       38043 :     return GetFastEnumPropertyKeys(isolate, object);
     807        6593 :   } else if (object->IsJSGlobalObject()) {
     808             :     return GetOwnEnumPropertyDictionaryKeys(
     809             :         isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
     810          18 :         JSGlobalObject::cast(*object)->global_dictionary());
     811             :   } else {
     812             :     return GetOwnEnumPropertyDictionaryKeys(
     813             :         isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
     814        6575 :         object->property_dictionary());
     815             :   }
     816             : }
     817             : 
     818             : namespace {
     819             : 
     820             : class NameComparator {
     821             :  public:
     822             :   explicit NameComparator(Isolate* isolate) : isolate_(isolate) {}
     823             : 
     824             :   bool operator()(uint32_t hash1, uint32_t hash2, const Handle<Name>& key1,
     825             :                   const Handle<Name>& key2) const {
     826        1016 :     return Name::Equals(isolate_, key1, key2);
     827             :   }
     828             : 
     829             :  private:
     830             :   Isolate* isolate_;
     831             : };
     832             : 
     833             : }  // namespace
     834             : 
     835             : // ES6 #sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
     836             : // Returns |true| on success, |nothing| in case of exception.
     837      947037 : Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver,
     838             :                                                   Handle<JSProxy> proxy) {
     839     1894074 :   STACK_CHECK(isolate_, Nothing<bool>());
     840      947026 :   if (filter_ == PRIVATE_NAMES_ONLY) {
     841          50 :     NameDictionary::CollectKeysTo(
     842          50 :         handle(proxy->property_dictionary(), isolate_), this);
     843             :     return Just(true);
     844             :   }
     845             : 
     846             :   // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
     847      947001 :   Handle<Object> handler(proxy->handler(), isolate_);
     848             :   // 2. If handler is null, throw a TypeError exception.
     849             :   // 3. Assert: Type(handler) is Object.
     850      947001 :   if (proxy->IsRevoked()) {
     851          54 :     isolate_->Throw(*isolate_->factory()->NewTypeError(
     852          54 :         MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string()));
     853             :     return Nothing<bool>();
     854             :   }
     855             :   // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
     856      946983 :   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate_);
     857             :   // 5. Let trap be ? GetMethod(handler, "ownKeys").
     858             :   Handle<Object> trap;
     859     2840949 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     860             :       isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
     861             :                                         isolate_->factory()->ownKeys_string()),
     862             :       Nothing<bool>());
     863             :   // 6. If trap is undefined, then
     864     1893894 :   if (trap->IsUndefined(isolate_)) {
     865             :     // 6a. Return target.[[OwnPropertyKeys]]().
     866      938656 :     return CollectOwnJSProxyTargetKeys(proxy, target);
     867             :   }
     868             :   // 7. Let trapResultArray be Call(trap, handler, «target»).
     869             :   Handle<Object> trap_result_array;
     870             :   Handle<Object> args[] = {target};
     871       16582 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     872             :       isolate_, trap_result_array,
     873             :       Execution::Call(isolate_, trap, handler, arraysize(args), args),
     874             :       Nothing<bool>());
     875             :   // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
     876             :   //    «String, Symbol»).
     877             :   Handle<FixedArray> trap_result;
     878        2340 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     879             :       isolate_, trap_result,
     880             :       Object::CreateListFromArrayLike(isolate_, trap_result_array,
     881             :                                       ElementTypes::kStringAndSymbol),
     882             :       Nothing<bool>());
     883             :   // 9. If trapResult contains any duplicate entries, throw a TypeError
     884             :   // exception. Combine with step 18
     885             :   // 18. Let uncheckedResultKeys be a new List which is a copy of trapResult.
     886        2106 :   Zone set_zone(isolate_->allocator(), ZONE_NAME);
     887             :   ZoneAllocationPolicy alloc(&set_zone);
     888             :   const int kPresent = 1;
     889             :   const int kGone = 0;
     890             :   base::TemplateHashMapImpl<Handle<Name>, int, NameComparator,
     891             :                             ZoneAllocationPolicy>
     892             :       unchecked_result_keys(ZoneHashMap::kDefaultHashMapCapacity,
     893        1053 :                             NameComparator(isolate_), alloc);
     894             :   int unchecked_result_keys_size = 0;
     895        6525 :   for (int i = 0; i < trap_result->length(); ++i) {
     896        2817 :     Handle<Name> key(Name::cast(trap_result->get(i)), isolate_);
     897        5634 :     auto entry = unchecked_result_keys.LookupOrInsert(key, key->Hash(), alloc);
     898        2817 :     if (entry->value != kPresent) {
     899        2736 :       entry->value = kPresent;
     900        2736 :       unchecked_result_keys_size++;
     901             :     } else {
     902             :       // found dupes, throw exception
     903         243 :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     904         162 :           MessageTemplate::kProxyOwnKeysDuplicateEntries));
     905          81 :       return Nothing<bool>();
     906             :     }
     907             :   }
     908             :   // 10. Let extensibleTarget be ? IsExtensible(target).
     909         972 :   Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
     910         972 :   MAYBE_RETURN(maybe_extensible, Nothing<bool>());
     911             :   bool extensible_target = maybe_extensible.FromJust();
     912             :   // 11. Let targetKeys be ? target.[[OwnPropertyKeys]]().
     913             :   Handle<FixedArray> target_keys;
     914        1944 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, target_keys,
     915             :                                    JSReceiver::OwnPropertyKeys(target),
     916             :                                    Nothing<bool>());
     917             :   // 12, 13. (Assert)
     918             :   // 14. Let targetConfigurableKeys be an empty List.
     919             :   // To save memory, we're re-using target_keys and will modify it in-place.
     920             :   Handle<FixedArray> target_configurable_keys = target_keys;
     921             :   // 15. Let targetNonconfigurableKeys be an empty List.
     922             :   Handle<FixedArray> target_nonconfigurable_keys =
     923         972 :       isolate_->factory()->NewFixedArray(target_keys->length());
     924             :   int nonconfigurable_keys_length = 0;
     925             :   // 16. Repeat, for each element key of targetKeys:
     926        2340 :   for (int i = 0; i < target_keys->length(); ++i) {
     927             :     // 16a. Let desc be ? target.[[GetOwnProperty]](key).
     928             :     PropertyDescriptor desc;
     929             :     Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
     930        1368 :         isolate_, target, handle(target_keys->get(i), isolate_), &desc);
     931         684 :     MAYBE_RETURN(found, Nothing<bool>());
     932             :     // 16b. If desc is not undefined and desc.[[Configurable]] is false, then
     933        1368 :     if (found.FromJust() && !desc.configurable()) {
     934             :       // 16b i. Append key as an element of targetNonconfigurableKeys.
     935         486 :       target_nonconfigurable_keys->set(nonconfigurable_keys_length,
     936         243 :                                        target_keys->get(i));
     937         243 :       nonconfigurable_keys_length++;
     938             :       // The key was moved, null it out in the original list.
     939         243 :       target_keys->set(i, Smi::kZero);
     940             :     } else {
     941             :       // 16c. Else,
     942             :       // 16c i. Append key as an element of targetConfigurableKeys.
     943             :       // (No-op, just keep it in |target_keys|.)
     944             :     }
     945             :   }
     946             :   // 17. If extensibleTarget is true and targetNonconfigurableKeys is empty,
     947             :   //     then:
     948         972 :   if (extensible_target && nonconfigurable_keys_length == 0) {
     949             :     // 17a. Return trapResult.
     950         828 :     return AddKeysFromJSProxy(proxy, trap_result);
     951             :   }
     952             :   // 18. (Done in step 9)
     953             :   // 19. Repeat, for each key that is an element of targetNonconfigurableKeys:
     954         612 :   for (int i = 0; i < nonconfigurable_keys_length; ++i) {
     955             :     Object raw_key = target_nonconfigurable_keys->get(i);
     956         243 :     Handle<Name> key(Name::cast(raw_key), isolate_);
     957             :     // 19a. If key is not an element of uncheckedResultKeys, throw a
     958             :     //      TypeError exception.
     959         486 :     auto found = unchecked_result_keys.Lookup(key, key->Hash());
     960         243 :     if (found == nullptr || found->value == kGone) {
     961          27 :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     962          18 :           MessageTemplate::kProxyOwnKeysMissing, key));
     963           9 :       return Nothing<bool>();
     964             :     }
     965             :     // 19b. Remove key from uncheckedResultKeys.
     966         234 :     found->value = kGone;
     967         234 :     unchecked_result_keys_size--;
     968             :   }
     969             :   // 20. If extensibleTarget is true, return trapResult.
     970         135 :   if (extensible_target) {
     971          54 :     return AddKeysFromJSProxy(proxy, trap_result);
     972             :   }
     973             :   // 21. Repeat, for each key that is an element of targetConfigurableKeys:
     974         621 :   for (int i = 0; i < target_configurable_keys->length(); ++i) {
     975             :     Object raw_key = target_configurable_keys->get(i);
     976         441 :     if (raw_key->IsSmi()) continue;  // Zapped entry, was nonconfigurable.
     977          99 :     Handle<Name> key(Name::cast(raw_key), isolate_);
     978             :     // 21a. If key is not an element of uncheckedResultKeys, throw a
     979             :     //      TypeError exception.
     980         198 :     auto found = unchecked_result_keys.Lookup(key, key->Hash());
     981          99 :     if (found == nullptr || found->value == kGone) {
     982           0 :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     983           0 :           MessageTemplate::kProxyOwnKeysMissing, key));
     984           0 :       return Nothing<bool>();
     985             :     }
     986             :     // 21b. Remove key from uncheckedResultKeys.
     987          99 :     found->value = kGone;
     988          99 :     unchecked_result_keys_size--;
     989             :   }
     990             :   // 22. If uncheckedResultKeys is not empty, throw a TypeError exception.
     991          81 :   if (unchecked_result_keys_size != 0) {
     992             :     DCHECK_GT(unchecked_result_keys_size, 0);
     993          27 :     isolate_->Throw(*isolate_->factory()->NewTypeError(
     994          18 :         MessageTemplate::kProxyOwnKeysNonExtensible));
     995             :     return Nothing<bool>();
     996             :   }
     997             :   // 23. Return trapResult.
     998          72 :   return AddKeysFromJSProxy(proxy, trap_result);
     999             : }
    1000             : 
    1001      938656 : Maybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys(
    1002             :     Handle<JSProxy> proxy, Handle<JSReceiver> target) {
    1003             :   // TODO(cbruni): avoid creating another KeyAccumulator
    1004             :   Handle<FixedArray> keys;
    1005     1877312 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
    1006             :       isolate_, keys,
    1007             :       KeyAccumulator::GetKeys(
    1008             :           target, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
    1009             :           GetKeysConversion::kConvertToString, is_for_in_, skip_indices_),
    1010             :       Nothing<bool>());
    1011      922915 :   Maybe<bool> result = AddKeysFromJSProxy(proxy, keys);
    1012      922915 :   return result;
    1013             : }
    1014             : 
    1015             : }  // namespace internal
    1016      122004 : }  // namespace v8

Generated by: LCOV version 1.10