LCOV - code coverage report
Current view: top level - src - keys.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 390 399 97.7 %
Date: 2019-03-21 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     1417246 : 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     1417246 :   return accumulator.GetKeys(keys_conversion);
      46             : }
      47             : 
      48     1262730 : Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
      49     1262730 :   if (keys_.is_null()) {
      50     1010940 :     return isolate_->factory()->empty_fixed_array();
      51             :   }
      52      496286 :   if (mode_ == KeyCollectionMode::kOwnOnly &&
      53      244496 :       keys_->map() == ReadOnlyRoots(isolate_).fixed_array_map()) {
      54             :     return Handle<FixedArray>::cast(keys_);
      55             :   }
      56             :   USE(ContainsOnlyValidKeys);
      57             :   Handle<FixedArray> result =
      58      250126 :       OrderedHashSet::ConvertToKeysArray(isolate(), keys(), convert);
      59             :   DCHECK(ContainsOnlyValidKeys(result));
      60      250126 :   return result;
      61             : }
      62             : 
      63           0 : Handle<OrderedHashSet> KeyAccumulator::keys() {
      64           0 :   return Handle<OrderedHashSet>::cast(keys_);
      65             : }
      66             : 
      67     3948985 : void KeyAccumulator::AddKey(Object key, AddKeyConversion convert) {
      68     7897970 :   AddKey(handle(key, isolate_), convert);
      69     3948985 : }
      70             : 
      71    10050549 : void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
      72    10050549 :   if (filter_ == PRIVATE_NAMES_ONLY) {
      73        9473 :     if (!key->IsSymbol()) return;
      74          95 :     if (!Symbol::cast(*key)->is_private_name()) return;
      75    10050454 :   } else if (key->IsSymbol()) {
      76       45717 :     if (filter_ & SKIP_SYMBOLS) return;
      77             : 
      78       45660 :     if (Symbol::cast(*key)->is_private()) return;
      79    10004737 :   } else if (filter_ & SKIP_STRINGS) {
      80             :     return;
      81             :   }
      82             : 
      83    10050486 :   if (IsShadowed(key)) return;
      84    10041171 :   if (keys_.is_null()) {
      85      250159 :     keys_ = OrderedHashSet::Allocate(isolate_, 16);
      86             :   }
      87             :   uint32_t index;
      88    20085244 :   if (convert == CONVERT_TO_ARRAY_INDEX && key->IsString() &&
      89    10042328 :       Handle<String>::cast(key)->AsArrayIndex(&index)) {
      90         374 :     key = isolate_->factory()->NewNumberFromUint(index);
      91             :   }
      92    10041171 :   Handle<OrderedHashSet> new_set = OrderedHashSet::Add(isolate(), keys(), key);
      93    10041171 :   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      195600 :     keys_->set(OrderedHashSet::NextTableIndex(), Smi::kZero);
      98      195600 :     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     1279555 : 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     2551232 :   if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) {
     175       48632 :     MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)),
     176             :                  Nothing<bool>());
     177             :     return Just(true);
     178             :   }
     179             : 
     180     1255239 :   PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly
     181             :                                           ? PrototypeIterator::END_AT_NON_HIDDEN
     182     1255239 :                                           : PrototypeIterator::END_AT_NULL;
     183     4752565 :   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     2243694 :     if (HasShadowingKeys()) skip_shadow_check_ = false;
     188             :     Handle<JSReceiver> current =
     189             :         PrototypeIterator::GetCurrent<JSReceiver>(iter);
     190             :     Maybe<bool> result = Just(false);  // Dummy initialization.
     191     2243694 :     if (current->IsJSProxy()) {
     192      922196 :       result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current));
     193             :     } else {
     194             :       DCHECK(current->IsJSObject());
     195     1321498 :       result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current));
     196             :     }
     197     2243694 :     MAYBE_RETURN(result, Nothing<bool>());
     198     2243538 :     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     2243501 :     if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
     202             :       return Nothing<bool>();
     203             :     }
     204     2246531 :     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    10050486 : bool KeyAccumulator::IsShadowed(Handle<Object> key) {
     215    10050486 :   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        4666 : void TrySettingEmptyEnumCache(JSReceiver object) {
     234        4666 :   Map map = object->map();
     235             :   DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
     236        5678 :   if (!map->OnlyHasSimpleProperties()) return;
     237        3996 :   if (map->IsJSProxyMap()) return;
     238        3996 :   if (map->NumberOfEnumerableProperties() > 0) return;
     239             :   DCHECK(object->IsJSObject());
     240        3654 :   map->SetEnumLength(0);
     241             : }
     242             : 
     243      101540 : bool CheckAndInitalizeEmptyEnumCache(JSReceiver object) {
     244      101540 :   if (object->map()->EnumLength() == kInvalidEnumCacheSentinel) {
     245        4666 :     TrySettingEmptyEnumCache(object);
     246             :   }
     247      101540 :   if (object->map()->EnumLength() != 0) return false;
     248             :   DCHECK(object->IsJSObject());
     249      100060 :   return !JSObject::cast(object)->HasEnumerableElements();
     250             : }
     251             : }  // namespace
     252             : 
     253     1471474 : void FastKeyAccumulator::Prepare() {
     254             :   DisallowHeapAllocation no_gc;
     255             :   // Directly go for the fast path for OWN_ONLY keys.
     256     1471474 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     257             :   // Fully walk the prototype chain and find the last prototype with keys.
     258       54228 :   is_receiver_simple_enum_ = false;
     259       54228 :   has_empty_prototype_ = true;
     260             :   JSReceiver last_prototype;
     261      311536 :   for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
     262      101540 :        iter.Advance()) {
     263             :     JSReceiver current = iter.GetCurrent<JSReceiver>();
     264      101540 :     bool has_no_properties = CheckAndInitalizeEmptyEnumCache(current);
     265      101540 :     if (has_no_properties) continue;
     266             :     last_prototype = current;
     267        1525 :     has_empty_prototype_ = false;
     268             :   }
     269       54228 :   if (has_empty_prototype_) {
     270             :     is_receiver_simple_enum_ =
     271       96836 :         receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
     272       96836 :         !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      174901 : Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
     281             :                                       Handle<FixedArray> array, int length) {
     282             :   DCHECK_LE(length, array->length());
     283      174901 :   if (array->length() == length) return array;
     284         271 :   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      223094 : 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      223094 :   if (enum_length != kInvalidEnumCacheSentinel) {
     299             :     DCHECK(map->OnlyHasSimpleProperties());
     300             :     DCHECK_LE(enum_length, keys->length());
     301             :     DCHECK_EQ(enum_length, map->NumberOfEnumerableProperties());
     302      148591 :     isolate->counters()->enum_cache_hits()->Increment();
     303      148591 :     return ReduceFixedArrayTo(isolate, keys, enum_length);
     304             :   }
     305             : 
     306             :   // Determine the actual number of enumerable properties of the {map}.
     307       74503 :   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       74503 :   if (enum_length <= keys->length()) {
     312       32206 :     if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
     313       26310 :     isolate->counters()->enum_cache_hits()->Increment();
     314       26310 :     return ReduceFixedArrayTo(isolate, keys, enum_length);
     315             :   }
     316             : 
     317             :   Handle<DescriptorArray> descriptors =
     318             :       Handle<DescriptorArray>(map->instance_descriptors(), isolate);
     319       48193 :   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       48193 :   keys = isolate->factory()->NewFixedArray(enum_length);
     326      677093 :   for (int i = 0; i < nod; i++) {
     327             :     DisallowHeapAllocation no_gc;
     328      314450 :     PropertyDetails details = descriptors->GetDetails(i);
     329      314450 :     if (details.IsDontEnum()) continue;
     330      303735 :     Object key = descriptors->GetKey(i);
     331      303735 :     if (key->IsSymbol()) continue;
     332      303606 :     keys->set(index, key);
     333      303606 :     if (details.location() != kField) fields_only = false;
     334      303606 :     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       48193 :   if (fields_only) {
     341       48055 :     indices = isolate->factory()->NewFixedArray(enum_length);
     342             :     index = 0;
     343      675773 :     for (int i = 0; i < nod; i++) {
     344             :       DisallowHeapAllocation no_gc;
     345      313859 :       PropertyDetails details = descriptors->GetDetails(i);
     346      324545 :       if (details.IsDontEnum()) continue;
     347      303302 :       Object key = descriptors->GetKey(i);
     348      303302 :       if (key->IsSymbol()) continue;
     349             :       DCHECK_EQ(kData, details.kind());
     350             :       DCHECK_EQ(kField, details.location());
     351      303173 :       FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
     352             :       indices->set(index, Smi::FromInt(field_index.GetLoadByFieldIndex()));
     353      303173 :       index++;
     354             :     }
     355             :     DCHECK_EQ(index, indices->length());
     356             :   }
     357             : 
     358             :   DescriptorArray::InitializeOrChangeEnumCache(descriptors, isolate, keys,
     359       48193 :                                                indices);
     360       96288 :   if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
     361             : 
     362       48193 :   return keys;
     363             : }
     364             : 
     365             : template <bool fast_properties>
     366      142034 : MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate,
     367             :                                                Handle<JSObject> object,
     368             :                                                GetKeysConversion convert,
     369             :                                                bool skip_indices) {
     370             :   Handle<FixedArray> keys;
     371      142034 :   ElementsAccessor* accessor = object->GetElementsAccessor();
     372             :   if (fast_properties) {
     373      135649 :     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      142034 :   if (skip_indices) {
     381             :     result = keys;
     382             :   } else {
     383      141930 :     result =
     384             :         accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE);
     385             :   }
     386             : 
     387      142034 :   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      142034 :   return result;
     392             : }
     393             : 
     394             : }  // namespace
     395             : 
     396     1468625 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(
     397             :     GetKeysConversion keys_conversion) {
     398     1468625 :   if (filter_ == ENUMERABLE_STRINGS) {
     399             :     Handle<FixedArray> keys;
     400      472544 :     if (GetKeysFast(keys_conversion).ToHandle(&keys)) {
     401      195688 :       return keys;
     402             :     }
     403       81168 :     if (isolate_->has_pending_exception()) return MaybeHandle<FixedArray>();
     404             :   }
     405             : 
     406     1272937 :   return GetKeysSlow(keys_conversion);
     407             : }
     408             : 
     409      236272 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
     410             :     GetKeysConversion keys_conversion) {
     411      236272 :   bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly;
     412             :   Map map = receiver_->map();
     413      471104 :   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      195688 :   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      189303 :   if (enum_length == kInvalidEnumCacheSentinel) {
     428             :     Handle<FixedArray> keys;
     429             :     // Try initializing the enum cache and return own properties.
     430      111588 :     if (GetOwnKeysWithUninitializedEnumCache().ToHandle(&keys)) {
     431       53654 :       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       53654 :           object->map()->EnumLength() != kInvalidEnumCacheSentinel;
     437       53654 :       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      135649 :                                       skip_indices_);
     444             : }
     445             : 
     446             : MaybeHandle<FixedArray>
     447       55794 : FastKeyAccumulator::GetOwnKeysWithUninitializedEnumCache() {
     448             :   Handle<JSObject> object = Handle<JSObject>::cast(receiver_);
     449             :   // Uninitalized enum cache
     450       55794 :   Map map = object->map();
     451       55794 :   if (object->elements()->length() != 0) {
     452             :     // Assume that there are elements.
     453        2140 :     return MaybeHandle<FixedArray>();
     454             :   }
     455             :   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
     456       53654 :   if (number_of_own_descriptors == 0) {
     457        4252 :     map->SetEnumLength(0);
     458        8504 :     return isolate_->factory()->empty_fixed_array();
     459             :   }
     460             :   // We have no elements but possibly enumerable property keys, hence we can
     461             :   // directly initialize the enum cache.
     462       49402 :   Handle<FixedArray> keys = GetFastEnumPropertyKeys(isolate_, object);
     463       49402 :   if (is_for_in_) return keys;
     464             :   // Do not leak the enum cache as it might end up as an elements backing store.
     465       44749 :   return isolate_->factory()->CopyFixedArray(keys);
     466             : }
     467             : 
     468     1272937 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
     469             :     GetKeysConversion keys_conversion) {
     470     1272937 :   KeyAccumulator accumulator(isolate_, mode_, filter_);
     471     1272937 :   accumulator.set_is_for_in(is_for_in_);
     472     1272937 :   accumulator.set_skip_indices(skip_indices_);
     473             :   accumulator.set_last_non_empty_prototype(last_non_empty_prototype_);
     474             : 
     475     2545874 :   MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_),
     476             :                MaybeHandle<FixedArray>());
     477     1250145 :   return accumulator.GetKeys(keys_conversion);
     478             : }
     479             : 
     480             : namespace {
     481             : 
     482             : enum IndexedOrNamed { kIndexed, kNamed };
     483             : 
     484          60 : void FilterForEnumerableProperties(Handle<JSReceiver> receiver,
     485             :                                    Handle<JSObject> object,
     486             :                                    Handle<InterceptorInfo> interceptor,
     487             :                                    KeyAccumulator* accumulator,
     488             :                                    Handle<JSObject> result,
     489             :                                    IndexedOrNamed type) {
     490             :   DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements());
     491          60 :   ElementsAccessor* accessor = result->GetElementsAccessor();
     492             : 
     493         120 :   uint32_t length = accessor->GetCapacity(*result, result->elements());
     494         504 :   for (uint32_t i = 0; i < length; i++) {
     495         510 :     if (!accessor->HasEntry(*result, i)) continue;
     496             : 
     497             :     // args are invalid after args.Call(), create a new one in every iteration.
     498             :     PropertyCallbackArguments args(accumulator->isolate(), interceptor->data(),
     499         312 :                                    *receiver, *object, Just(kDontThrow));
     500             : 
     501         156 :     Handle<Object> element = accessor->Get(result, i);
     502             :     Handle<Object> attributes;
     503         156 :     if (type == kIndexed) {
     504             :       uint32_t number;
     505          84 :       CHECK(element->ToUint32(&number));
     506          84 :       attributes = args.CallIndexedQuery(interceptor, number);
     507             :     } else {
     508          72 :       CHECK(element->IsName());
     509             :       attributes =
     510          72 :           args.CallNamedQuery(interceptor, Handle<Name>::cast(element));
     511             :     }
     512             : 
     513         156 :     if (!attributes.is_null()) {
     514             :       int32_t value;
     515         144 :       CHECK(attributes->ToInt32(&value));
     516         144 :       if ((value & DONT_ENUM) == 0) {
     517          48 :         accumulator->AddKey(element, DO_NOT_CONVERT);
     518             :       }
     519             :     }
     520             :   }
     521          60 : }
     522             : 
     523             : // Returns |true| on success, |nothing| on exception.
     524         475 : Maybe<bool> CollectInterceptorKeysInternal(Handle<JSReceiver> receiver,
     525             :                                            Handle<JSObject> object,
     526             :                                            Handle<InterceptorInfo> interceptor,
     527             :                                            KeyAccumulator* accumulator,
     528             :                                            IndexedOrNamed type) {
     529             :   Isolate* isolate = accumulator->isolate();
     530             :   PropertyCallbackArguments enum_args(isolate, interceptor->data(), *receiver,
     531         950 :                                       *object, Just(kDontThrow));
     532             : 
     533             :   Handle<JSObject> result;
     534         475 :   if (!interceptor->enumerator()->IsUndefined(isolate)) {
     535         475 :     if (type == kIndexed) {
     536         235 :       result = enum_args.CallIndexedEnumerator(interceptor);
     537             :     } else {
     538             :       DCHECK_EQ(type, kNamed);
     539         240 :       result = enum_args.CallNamedEnumerator(interceptor);
     540             :     }
     541             :   }
     542         475 :   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
     543         445 :   if (result.is_null()) return Just(true);
     544             : 
     545         488 :   if ((accumulator->filter() & ONLY_ENUMERABLE) &&
     546             :       !interceptor->query()->IsUndefined(isolate)) {
     547             :     FilterForEnumerableProperties(receiver, object, interceptor, accumulator,
     548          60 :                                   result, type);
     549             :   } else {
     550         309 :     accumulator->AddKeys(
     551         309 :         result, type == kIndexed ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
     552             :   }
     553             :   return Just(true);
     554             : }
     555             : 
     556     2453449 : Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver,
     557             :                                    Handle<JSObject> object,
     558             :                                    KeyAccumulator* accumulator,
     559             :                                    IndexedOrNamed type) {
     560             :   Isolate* isolate = accumulator->isolate();
     561     2453449 :   if (type == kIndexed) {
     562     1229144 :     if (!object->HasIndexedInterceptor()) return Just(true);
     563             :   } else {
     564     1224305 :     if (!object->HasNamedInterceptor()) return Just(true);
     565             :   }
     566             :   Handle<InterceptorInfo> interceptor(type == kIndexed
     567         865 :                                           ? object->GetIndexedInterceptor()
     568         655 :                                           : object->GetNamedInterceptor(),
     569        1090 :                                       isolate);
     570         435 :   if ((accumulator->filter() & ONLY_ALL_CAN_READ) &&
     571             :       !interceptor->all_can_read()) {
     572             :     return Just(true);
     573             :   }
     574             :   return CollectInterceptorKeysInternal(receiver, object, interceptor,
     575         435 :                                         accumulator, type);
     576             : }
     577             : 
     578             : }  // namespace
     579             : 
     580     1229732 : Maybe<bool> KeyAccumulator::CollectOwnElementIndices(
     581             :     Handle<JSReceiver> receiver, Handle<JSObject> object) {
     582     1229732 :   if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true);
     583             : 
     584     1229144 :   ElementsAccessor* accessor = object->GetElementsAccessor();
     585     1229144 :   accessor->CollectElementIndices(object, this);
     586             : 
     587     1229144 :   return CollectInterceptorKeys(receiver, object, this, kIndexed);
     588             : }
     589             : 
     590             : namespace {
     591             : 
     592             : template <bool skip_symbols>
     593     1227065 : int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
     594             :                                     KeyAccumulator* keys,
     595             :                                     Handle<DescriptorArray> descs,
     596             :                                     int start_index, int limit) {
     597             :   int first_skipped = -1;
     598             :   PropertyFilter filter = keys->filter();
     599             :   KeyCollectionMode mode = keys->mode();
     600     4036421 :   for (int i = start_index; i < limit; i++) {
     601             :     bool is_shadowing_key = false;
     602     1404678 :     PropertyDetails details = descs->GetDetails(i);
     603             : 
     604     1404678 :     if ((details.attributes() & filter) != 0) {
     605          12 :       if (mode == KeyCollectionMode::kIncludePrototypes) {
     606             :         is_shadowing_key = true;
     607             :       } else {
     608      375848 :         continue;
     609             :       }
     610             :     }
     611             : 
     612     1404666 :     if (filter & ONLY_ALL_CAN_READ) {
     613          18 :       if (details.kind() != kAccessor) continue;
     614           6 :       Object accessors = descs->GetStrongValue(i);
     615           6 :       if (!accessors->IsAccessorInfo()) continue;
     616           6 :       if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
     617             :     }
     618             : 
     619     1404660 :     Name key = descs->GetKey(i);
     620     1404660 :     if (skip_symbols == key->IsSymbol()) {
     621      363208 :       if (first_skipped == -1) first_skipped = i;
     622             :       continue;
     623             :     }
     624     1041452 :     if (key->FilterKey(keys->filter())) continue;
     625             : 
     626     1028830 :     if (is_shadowing_key) {
     627           0 :       keys->AddShadowingKey(key);
     628             :     } else {
     629     1028830 :       keys->AddKey(key, DO_NOT_CONVERT);
     630             :     }
     631             :   }
     632     1227065 :   return first_skipped;
     633             : }
     634             : 
     635             : template <class T>
     636       43191 : Handle<FixedArray> GetOwnEnumPropertyDictionaryKeys(Isolate* isolate,
     637             :                                                     KeyCollectionMode mode,
     638             :                                                     KeyAccumulator* accumulator,
     639             :                                                     Handle<JSObject> object,
     640             :                                                     T raw_dictionary) {
     641             :   Handle<T> dictionary(raw_dictionary, isolate);
     642       43191 :   if (dictionary->NumberOfElements() == 0) {
     643             :     return isolate->factory()->empty_fixed_array();
     644             :   }
     645       42917 :   int length = dictionary->NumberOfEnumerableProperties();
     646       42917 :   Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
     647       42917 :   T::CopyEnumKeysTo(isolate, dictionary, storage, mode, accumulator);
     648       42917 :   return storage;
     649             : }
     650             : }  // namespace
     651             : 
     652     1224359 : Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver,
     653             :                                                     Handle<JSObject> object) {
     654     1224359 :   if (filter_ == ENUMERABLE_STRINGS) {
     655             :     Handle<FixedArray> enum_keys;
     656       72110 :     if (object->HasFastProperties()) {
     657       35512 :       enum_keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, object);
     658             :       // If the number of properties equals the length of enumerable properties
     659             :       // we do not have to filter out non-enumerable ones
     660             :       Map map = object->map();
     661             :       int nof_descriptors = map->NumberOfOwnDescriptors();
     662       35512 :       if (enum_keys->length() != nof_descriptors) {
     663             :         Handle<DescriptorArray> descs =
     664        8972 :             Handle<DescriptorArray>(map->instance_descriptors(), isolate_);
     665      230270 :         for (int i = 0; i < nof_descriptors; i++) {
     666      110649 :           PropertyDetails details = descs->GetDetails(i);
     667      114208 :           if (!details.IsDontEnum()) continue;
     668      107090 :           Object key = descs->GetKey(i);
     669      107090 :           this->AddShadowingKey(key);
     670             :         }
     671             :       }
     672       36598 :     } else if (object->IsJSGlobalObject()) {
     673             :       enum_keys = GetOwnEnumPropertyDictionaryKeys(
     674             :           isolate_, mode_, this, object,
     675       36269 :           JSGlobalObject::cast(*object)->global_dictionary());
     676             :     } else {
     677             :       enum_keys = GetOwnEnumPropertyDictionaryKeys(
     678         329 :           isolate_, mode_, this, object, object->property_dictionary());
     679             :     }
     680       72110 :     if (object->IsJSModuleNamespace()) {
     681             :       // Simulate [[GetOwnProperty]] for establishing enumerability, which
     682             :       // throws for uninitialized exports.
     683         504 :       for (int i = 0, n = enum_keys->length(); i < n; ++i) {
     684         243 :         Handle<String> key(String::cast(enum_keys->get(i)), isolate_);
     685         243 :         if (Handle<JSModuleNamespace>::cast(object)
     686         486 :                 ->GetExport(isolate(), key)
     687             :                 .is_null()) {
     688          54 :           return Nothing<bool>();
     689             :         }
     690             :       }
     691             :     }
     692       72056 :     AddKeys(enum_keys, DO_NOT_CONVERT);
     693             :   } else {
     694     1152249 :     if (object->HasFastProperties()) {
     695             :       int limit = object->map()->NumberOfOwnDescriptors();
     696             :       Handle<DescriptorArray> descs(object->map()->instance_descriptors(),
     697     1128808 :                                     isolate_);
     698             :       // First collect the strings,
     699             :       int first_symbol =
     700     1128808 :           CollectOwnPropertyNamesInternal<true>(object, this, descs, 0, limit);
     701             :       // then the symbols.
     702     1128808 :       if (first_symbol != -1) {
     703             :         CollectOwnPropertyNamesInternal<false>(object, this, descs,
     704       19048 :                                                first_symbol, limit);
     705             :       }
     706       23441 :     } else if (object->IsJSGlobalObject()) {
     707       45346 :       GlobalDictionary::CollectKeysTo(
     708       45346 :           handle(JSGlobalObject::cast(*object)->global_dictionary(), isolate_),
     709       22673 :           this);
     710             :     } else {
     711        1536 :       NameDictionary::CollectKeysTo(
     712        1536 :           handle(object->property_dictionary(), isolate_), this);
     713             :     }
     714             :   }
     715             :   // Add the property keys from the interceptor.
     716     1224305 :   return CollectInterceptorKeys(receiver, object, this, kNamed);
     717             : }
     718             : 
     719       97141 : void KeyAccumulator::CollectPrivateNames(Handle<JSReceiver> receiver,
     720             :                                          Handle<JSObject> object) {
     721       97141 :   if (object->HasFastProperties()) {
     722             :     int limit = object->map()->NumberOfOwnDescriptors();
     723             :     Handle<DescriptorArray> descs(object->map()->instance_descriptors(),
     724       79209 :                                   isolate_);
     725       79209 :     CollectOwnPropertyNamesInternal<false>(object, this, descs, 0, limit);
     726       17932 :   } else if (object->IsJSGlobalObject()) {
     727       35786 :     GlobalDictionary::CollectKeysTo(
     728       35786 :         handle(JSGlobalObject::cast(*object)->global_dictionary(), isolate_),
     729       17893 :         this);
     730             :   } else {
     731          78 :     NameDictionary::CollectKeysTo(
     732          78 :         handle(object->property_dictionary(), isolate_), this);
     733             :   }
     734       97141 : }
     735             : 
     736          20 : Maybe<bool> KeyAccumulator::CollectAccessCheckInterceptorKeys(
     737             :     Handle<AccessCheckInfo> access_check_info, Handle<JSReceiver> receiver,
     738             :     Handle<JSObject> object) {
     739          20 :   if (!skip_indices_) {
     740          60 :     MAYBE_RETURN((CollectInterceptorKeysInternal(
     741             :                      receiver, object,
     742             :                      handle(InterceptorInfo::cast(
     743             :                                 access_check_info->indexed_interceptor()),
     744             :                             isolate_),
     745             :                      this, kIndexed)),
     746             :                  Nothing<bool>());
     747             :   }
     748          60 :   MAYBE_RETURN(
     749             :       (CollectInterceptorKeysInternal(
     750             :           receiver, object,
     751             :           handle(InterceptorInfo::cast(access_check_info->named_interceptor()),
     752             :                  isolate_),
     753             :           this, kNamed)),
     754             :       Nothing<bool>());
     755             :   return Just(true);
     756             : }
     757             : 
     758             : // Returns |true| on success, |false| if prototype walking should be stopped,
     759             : // |nothing| if an exception was thrown.
     760     1321498 : Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
     761             :                                            Handle<JSObject> object) {
     762             :   // Check access rights if required.
     763     1321592 :   if (object->IsAccessCheckNeeded() &&
     764         188 :       !isolate_->MayAccess(handle(isolate_->context(), isolate_), object)) {
     765             :     // The cross-origin spec says that [[Enumerate]] shall return an empty
     766             :     // iterator when it doesn't have access...
     767          69 :     if (mode_ == KeyCollectionMode::kIncludePrototypes) {
     768             :       return Just(false);
     769             :     }
     770             :     // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
     771             :     DCHECK_EQ(KeyCollectionMode::kOwnOnly, mode_);
     772             :     Handle<AccessCheckInfo> access_check_info;
     773             :     {
     774             :       DisallowHeapAllocation no_gc;
     775          52 :       AccessCheckInfo maybe_info = AccessCheckInfo::Get(isolate_, object);
     776          52 :       if (!maybe_info.is_null()) {
     777          42 :         access_check_info = handle(maybe_info, isolate_);
     778             :       }
     779             :     }
     780             :     // We always have both kinds of interceptors or none.
     781          94 :     if (!access_check_info.is_null() &&
     782             :         access_check_info->named_interceptor() != Object()) {
     783          40 :       MAYBE_RETURN(CollectAccessCheckInterceptorKeys(access_check_info,
     784             :                                                      receiver, object),
     785             :                    Nothing<bool>());
     786             :       return Just(false);
     787             :     }
     788          32 :     filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ);
     789             :   }
     790     1321461 :   if (filter_ & PRIVATE_NAMES_ONLY) {
     791       97141 :     CollectPrivateNames(receiver, object);
     792             :     return Just(true);
     793             :   }
     794             : 
     795     2448640 :   MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>());
     796     2448616 :   MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>());
     797             :   return Just(true);
     798             : }
     799             : 
     800             : // static
     801       44636 : Handle<FixedArray> KeyAccumulator::GetOwnEnumPropertyKeys(
     802             :     Isolate* isolate, Handle<JSObject> object) {
     803       44636 :   if (object->HasFastProperties()) {
     804       38043 :     return GetFastEnumPropertyKeys(isolate, object);
     805        6593 :   } else if (object->IsJSGlobalObject()) {
     806             :     return GetOwnEnumPropertyDictionaryKeys(
     807             :         isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
     808          18 :         JSGlobalObject::cast(*object)->global_dictionary());
     809             :   } else {
     810             :     return GetOwnEnumPropertyDictionaryKeys(
     811             :         isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
     812        6575 :         object->property_dictionary());
     813             :   }
     814             : }
     815             : 
     816             : namespace {
     817             : 
     818             : class NameComparator {
     819             :  public:
     820             :   explicit NameComparator(Isolate* isolate) : isolate_(isolate) {}
     821             : 
     822             :   bool operator()(uint32_t hash1, uint32_t hash2, const Handle<Name>& key1,
     823             :                   const Handle<Name>& key2) const {
     824         806 :     return Name::Equals(isolate_, key1, key2);
     825             :   }
     826             : 
     827             :  private:
     828             :   Isolate* isolate_;
     829             : };
     830             : 
     831             : }  // namespace
     832             : 
     833             : // ES6 #sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
     834             : // Returns |true| on success, |nothing| in case of exception.
     835      946512 : Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver,
     836             :                                                   Handle<JSProxy> proxy) {
     837     1893024 :   STACK_CHECK(isolate_, Nothing<bool>());
     838      946502 :   if (filter_ == PRIVATE_NAMES_ONLY) {
     839          50 :     NameDictionary::CollectKeysTo(
     840          50 :         handle(proxy->property_dictionary(), isolate_), this);
     841             :     return Just(true);
     842             :   }
     843             : 
     844             :   // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
     845      946477 :   Handle<Object> handler(proxy->handler(), isolate_);
     846             :   // 2. If handler is null, throw a TypeError exception.
     847             :   // 3. Assert: Type(handler) is Object.
     848      946477 :   if (proxy->IsRevoked()) {
     849          54 :     isolate_->Throw(*isolate_->factory()->NewTypeError(
     850          54 :         MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string()));
     851             :     return Nothing<bool>();
     852             :   }
     853             :   // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
     854      946459 :   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate_);
     855             :   // 5. Let trap be ? GetMethod(handler, "ownKeys").
     856             :   Handle<Object> trap;
     857     2839377 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     858             :       isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
     859             :                                         isolate_->factory()->ownKeys_string()),
     860             :       Nothing<bool>());
     861             :   // 6. If trap is undefined, then
     862     1892846 :   if (trap->IsUndefined(isolate_)) {
     863             :     // 6a. Return target.[[OwnPropertyKeys]]().
     864      938233 :     return CollectOwnJSProxyTargetKeys(proxy, target);
     865             :   }
     866             :   // 7. Let trapResultArray be Call(trap, handler, «target»).
     867             :   Handle<Object> trap_result_array;
     868             :   Handle<Object> args[] = {target};
     869       16380 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     870             :       isolate_, trap_result_array,
     871             :       Execution::Call(isolate_, trap, handler, arraysize(args), args),
     872             :       Nothing<bool>());
     873             :   // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
     874             :   //    «String, Symbol»).
     875             :   Handle<FixedArray> trap_result;
     876        2340 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     877             :       isolate_, trap_result,
     878             :       Object::CreateListFromArrayLike(isolate_, trap_result_array,
     879             :                                       ElementTypes::kStringAndSymbol),
     880             :       Nothing<bool>());
     881             :   // 9. If trapResult contains any duplicate entries, throw a TypeError
     882             :   // exception. Combine with step 18
     883             :   // 18. Let uncheckedResultKeys be a new List which is a copy of trapResult.
     884        2106 :   Zone set_zone(isolate_->allocator(), ZONE_NAME);
     885             :   ZoneAllocationPolicy alloc(&set_zone);
     886             :   const int kPresent = 1;
     887             :   const int kGone = 0;
     888             :   base::TemplateHashMapImpl<Handle<Name>, int, NameComparator,
     889             :                             ZoneAllocationPolicy>
     890             :       unchecked_result_keys(ZoneHashMap::kDefaultHashMapCapacity,
     891        1053 :                             NameComparator(isolate_), alloc);
     892             :   int unchecked_result_keys_size = 0;
     893        6525 :   for (int i = 0; i < trap_result->length(); ++i) {
     894        2817 :     Handle<Name> key(Name::cast(trap_result->get(i)), isolate_);
     895        5634 :     auto entry = unchecked_result_keys.LookupOrInsert(key, key->Hash(), alloc);
     896        2817 :     if (entry->value != kPresent) {
     897        2736 :       entry->value = kPresent;
     898        2736 :       unchecked_result_keys_size++;
     899             :     } else {
     900             :       // found dupes, throw exception
     901         243 :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     902         162 :           MessageTemplate::kProxyOwnKeysDuplicateEntries));
     903          81 :       return Nothing<bool>();
     904             :     }
     905             :   }
     906             :   // 10. Let extensibleTarget be ? IsExtensible(target).
     907         972 :   Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
     908         972 :   MAYBE_RETURN(maybe_extensible, Nothing<bool>());
     909             :   bool extensible_target = maybe_extensible.FromJust();
     910             :   // 11. Let targetKeys be ? target.[[OwnPropertyKeys]]().
     911             :   Handle<FixedArray> target_keys;
     912        1944 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, target_keys,
     913             :                                    JSReceiver::OwnPropertyKeys(target),
     914             :                                    Nothing<bool>());
     915             :   // 12, 13. (Assert)
     916             :   // 14. Let targetConfigurableKeys be an empty List.
     917             :   // To save memory, we're re-using target_keys and will modify it in-place.
     918             :   Handle<FixedArray> target_configurable_keys = target_keys;
     919             :   // 15. Let targetNonconfigurableKeys be an empty List.
     920             :   Handle<FixedArray> target_nonconfigurable_keys =
     921         972 :       isolate_->factory()->NewFixedArray(target_keys->length());
     922             :   int nonconfigurable_keys_length = 0;
     923             :   // 16. Repeat, for each element key of targetKeys:
     924        2340 :   for (int i = 0; i < target_keys->length(); ++i) {
     925             :     // 16a. Let desc be ? target.[[GetOwnProperty]](key).
     926             :     PropertyDescriptor desc;
     927             :     Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
     928        1368 :         isolate_, target, handle(target_keys->get(i), isolate_), &desc);
     929         684 :     MAYBE_RETURN(found, Nothing<bool>());
     930             :     // 16b. If desc is not undefined and desc.[[Configurable]] is false, then
     931        1368 :     if (found.FromJust() && !desc.configurable()) {
     932             :       // 16b i. Append key as an element of targetNonconfigurableKeys.
     933         486 :       target_nonconfigurable_keys->set(nonconfigurable_keys_length,
     934         243 :                                        target_keys->get(i));
     935         243 :       nonconfigurable_keys_length++;
     936             :       // The key was moved, null it out in the original list.
     937         243 :       target_keys->set(i, Smi::kZero);
     938             :     } else {
     939             :       // 16c. Else,
     940             :       // 16c i. Append key as an element of targetConfigurableKeys.
     941             :       // (No-op, just keep it in |target_keys|.)
     942             :     }
     943             :   }
     944             :   // 17. If extensibleTarget is true and targetNonconfigurableKeys is empty,
     945             :   //     then:
     946         972 :   if (extensible_target && nonconfigurable_keys_length == 0) {
     947             :     // 17a. Return trapResult.
     948         828 :     return AddKeysFromJSProxy(proxy, trap_result);
     949             :   }
     950             :   // 18. (Done in step 9)
     951             :   // 19. Repeat, for each key that is an element of targetNonconfigurableKeys:
     952         612 :   for (int i = 0; i < nonconfigurable_keys_length; ++i) {
     953             :     Object raw_key = target_nonconfigurable_keys->get(i);
     954         243 :     Handle<Name> key(Name::cast(raw_key), isolate_);
     955             :     // 19a. If key is not an element of uncheckedResultKeys, throw a
     956             :     //      TypeError exception.
     957         486 :     auto found = unchecked_result_keys.Lookup(key, key->Hash());
     958         243 :     if (found == nullptr || found->value == kGone) {
     959          27 :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     960          18 :           MessageTemplate::kProxyOwnKeysMissing, key));
     961           9 :       return Nothing<bool>();
     962             :     }
     963             :     // 19b. Remove key from uncheckedResultKeys.
     964         234 :     found->value = kGone;
     965         234 :     unchecked_result_keys_size--;
     966             :   }
     967             :   // 20. If extensibleTarget is true, return trapResult.
     968         135 :   if (extensible_target) {
     969          54 :     return AddKeysFromJSProxy(proxy, trap_result);
     970             :   }
     971             :   // 21. Repeat, for each key that is an element of targetConfigurableKeys:
     972         621 :   for (int i = 0; i < target_configurable_keys->length(); ++i) {
     973             :     Object raw_key = target_configurable_keys->get(i);
     974         441 :     if (raw_key->IsSmi()) continue;  // Zapped entry, was nonconfigurable.
     975          99 :     Handle<Name> key(Name::cast(raw_key), isolate_);
     976             :     // 21a. If key is not an element of uncheckedResultKeys, throw a
     977             :     //      TypeError exception.
     978         198 :     auto found = unchecked_result_keys.Lookup(key, key->Hash());
     979          99 :     if (found == nullptr || found->value == kGone) {
     980           0 :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     981           0 :           MessageTemplate::kProxyOwnKeysMissing, key));
     982           0 :       return Nothing<bool>();
     983             :     }
     984             :     // 21b. Remove key from uncheckedResultKeys.
     985          99 :     found->value = kGone;
     986          99 :     unchecked_result_keys_size--;
     987             :   }
     988             :   // 22. If uncheckedResultKeys is not empty, throw a TypeError exception.
     989          81 :   if (unchecked_result_keys_size != 0) {
     990             :     DCHECK_GT(unchecked_result_keys_size, 0);
     991          27 :     isolate_->Throw(*isolate_->factory()->NewTypeError(
     992          18 :         MessageTemplate::kProxyOwnKeysNonExtensible));
     993             :     return Nothing<bool>();
     994             :   }
     995             :   // 23. Return trapResult.
     996          72 :   return AddKeysFromJSProxy(proxy, trap_result);
     997             : }
     998             : 
     999      938233 : Maybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys(
    1000             :     Handle<JSProxy> proxy, Handle<JSReceiver> target) {
    1001             :   // TODO(cbruni): avoid creating another KeyAccumulator
    1002             :   Handle<FixedArray> keys;
    1003     1876466 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
    1004             :       isolate_, keys,
    1005             :       KeyAccumulator::GetKeys(
    1006             :           target, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
    1007             :           GetKeysConversion::kConvertToString, is_for_in_, skip_indices_),
    1008             :       Nothing<bool>());
    1009      922915 :   Maybe<bool> result = AddKeysFromJSProxy(proxy, keys);
    1010      922915 :   return result;
    1011             : }
    1012             : 
    1013             : }  // namespace internal
    1014      120216 : }  // namespace v8

Generated by: LCOV version 1.10