LCOV - code coverage report
Current view: top level - src - keys.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 385 391 98.5 %
Date: 2019-01-20 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/handles-inl.h"
      10             : #include "src/heap/factory.h"
      11             : #include "src/identity-map.h"
      12             : #include "src/isolate-inl.h"
      13             : #include "src/objects-inl.h"
      14             : #include "src/objects/api-callbacks.h"
      15             : #include "src/objects/hash-table-inl.h"
      16             : #include "src/objects/module-inl.h"
      17             : #include "src/property-descriptor.h"
      18             : #include "src/prototype.h"
      19             : 
      20             : namespace v8 {
      21             : namespace internal {
      22             : 
      23             : namespace {
      24             : 
      25             : static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
      26             :   int len = array->length();
      27             :   for (int i = 0; i < len; i++) {
      28             :     Object e = array->get(i);
      29             :     if (!(e->IsName() || e->IsNumber())) return false;
      30             :   }
      31             :   return true;
      32             : }
      33             : 
      34             : }  // namespace
      35             : 
      36             : // static
      37     1332406 : MaybeHandle<FixedArray> KeyAccumulator::GetKeys(
      38             :     Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter,
      39             :     GetKeysConversion keys_conversion, bool is_for_in, bool skip_indices) {
      40             :   Isolate* isolate = object->GetIsolate();
      41             :   FastKeyAccumulator accumulator(isolate, object, mode, filter, is_for_in,
      42             :                                  skip_indices);
      43     1332406 :   return accumulator.GetKeys(keys_conversion);
      44             : }
      45             : 
      46     1431845 : Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
      47     1182342 :   if (keys_.is_null()) {
      48      931126 :     return isolate_->factory()->empty_fixed_array();
      49             :   }
      50      495086 :   if (mode_ == KeyCollectionMode::kOwnOnly &&
      51      243870 :       keys_->map() == ReadOnlyRoots(isolate_).fixed_array_map()) {
      52        1713 :     return Handle<FixedArray>::cast(keys_);
      53             :   }
      54             :   USE(ContainsOnlyValidKeys);
      55             :   Handle<FixedArray> result =
      56      249503 :       OrderedHashSet::ConvertToKeysArray(isolate(), keys(), convert);
      57             :   DCHECK(ContainsOnlyValidKeys(result));
      58      249503 :   return result;
      59             : }
      60             : 
      61           0 : Handle<OrderedHashSet> KeyAccumulator::keys() {
      62    10241282 :   return Handle<OrderedHashSet>::cast(keys_);
      63             : }
      64             : 
      65     3937117 : void KeyAccumulator::AddKey(Object key, AddKeyConversion convert) {
      66     7874234 :   AddKey(handle(key, isolate_), convert);
      67     3937117 : }
      68             : 
      69    19992945 : void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
      70    20002332 :   if (key->IsSymbol()) {
      71       55116 :     if (filter_ & SKIP_SYMBOLS) return;
      72       91326 :     if (Handle<Symbol>::cast(key)->is_private()) return;
      73     9955437 :   } else if (filter_ & SKIP_STRINGS) {
      74             :     return;
      75             :   }
      76    10001094 :   if (IsShadowed(key)) return;
      77     9991779 :   if (keys_.is_null()) {
      78      249536 :     keys_ = OrderedHashSet::Allocate(isolate_, 16);
      79             :   }
      80             :   uint32_t index;
      81    19988367 :   if (convert == CONVERT_TO_ARRAY_INDEX && key->IsString() &&
      82     9994201 :       Handle<String>::cast(key)->AsArrayIndex(&index)) {
      83         392 :     key = isolate_->factory()->NewNumberFromUint(index);
      84             :   }
      85     9991779 :   Handle<OrderedHashSet> new_set = OrderedHashSet::Add(isolate(), keys(), key);
      86     9991779 :   if (*new_set != *keys_) {
      87             :     // The keys_ Set is converted directly to a FixedArray in GetKeys which can
      88             :     // be left-trimmer. Hence the previous Set should not keep a pointer to the
      89             :     // new one.
      90      178473 :     keys_->set(OrderedHashSet::NextTableIndex(), Smi::kZero);
      91      178473 :     keys_ = new_set;
      92             :   }
      93             : }
      94             : 
      95      994194 : void KeyAccumulator::AddKeys(Handle<FixedArray> array,
      96             :                              AddKeyConversion convert) {
      97             :   int add_length = array->length();
      98     3540524 :   for (int i = 0; i < add_length; i++) {
      99     2546330 :     Handle<Object> current(array->get(i), isolate_);
     100     2546330 :     AddKey(current, convert);
     101             :   }
     102      994194 : }
     103             : 
     104         309 : void KeyAccumulator::AddKeys(Handle<JSObject> array_like,
     105             :                              AddKeyConversion convert) {
     106             :   DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements());
     107         309 :   ElementsAccessor* accessor = array_like->GetElementsAccessor();
     108         309 :   accessor->AddElementsToKeyAccumulator(array_like, this, convert);
     109         309 : }
     110             : 
     111        3016 : MaybeHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator,
     112             :                                         Handle<JSProxy> owner,
     113             :                                         Handle<FixedArray> keys,
     114             :                                         PropertyFilter filter) {
     115        1832 :   if (filter == ALL_PROPERTIES) {
     116             :     // Nothing to do.
     117         648 :     return keys;
     118             :   }
     119             :   Isolate* isolate = accumulator->isolate();
     120             :   int store_position = 0;
     121        9518 :   for (int i = 0; i < keys->length(); ++i) {
     122             :     Handle<Name> key(Name::cast(keys->get(i)), isolate);
     123        3647 :     if (key->FilterKey(filter)) continue;  // Skip this key.
     124        3356 :     if (filter & ONLY_ENUMERABLE) {
     125             :       PropertyDescriptor desc;
     126             :       Maybe<bool> found =
     127        1709 :           JSProxy::GetOwnPropertyDescriptor(isolate, owner, key, &desc);
     128        1709 :       MAYBE_RETURN(found, MaybeHandle<FixedArray>());
     129        1880 :       if (!found.FromJust()) continue;
     130        1520 :       if (!desc.enumerable()) {
     131         126 :         accumulator->AddShadowingKey(key);
     132         126 :         continue;
     133             :       }
     134             :     }
     135             :     // Keep this key.
     136        3041 :     if (store_position != i) {
     137         450 :       keys->set(store_position, *key);
     138             :     }
     139        3041 :     store_position++;
     140             :   }
     141        1112 :   return FixedArray::ShrinkOrEmpty(isolate, keys, store_position);
     142             : }
     143             : 
     144             : // Returns "nothing" in case of exception, "true" on success.
     145      923927 : Maybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy,
     146             :                                                Handle<FixedArray> keys) {
     147             :   // Postpone the enumerable check for for-in to the ForInFilter step.
     148      923927 :   if (!is_for_in_) {
     149        3664 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     150             :         isolate_, keys, FilterProxyKeys(this, proxy, keys, filter_),
     151             :         Nothing<bool>());
     152        1760 :     if (mode_ == KeyCollectionMode::kOwnOnly) {
     153             :       // If we collect only the keys from a JSProxy do not sort or deduplicate.
     154        1713 :       keys_ = keys;
     155             :       return Just(true);
     156             :     }
     157             :   }
     158      922142 :   AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
     159             :   return Just(true);
     160             : }
     161             : 
     162     1195368 : Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
     163             :                                         Handle<JSReceiver> object) {
     164             :   // Proxies have no hidden prototype and we should not trigger the
     165             :   // [[GetPrototypeOf]] trap on the last iteration when using
     166             :   // AdvanceFollowingProxies.
     167     3570260 :   if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) {
     168       19833 :     MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)),
     169             :                  Nothing<bool>());
     170             :     return Just(true);
     171             :   }
     172             : 
     173     1175535 :   PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly
     174             :                                           ? PrototypeIterator::END_AT_NON_HIDDEN
     175     1175535 :                                           : PrototypeIterator::END_AT_NULL;
     176     4495592 :   for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end);
     177     3320057 :        !iter.IsAtEnd();) {
     178             :     // Start the shadow checks only after the first prototype has added
     179             :     // shadowing keys.
     180     2146084 :     if (HasShadowingKeys()) skip_shadow_check_ = false;
     181             :     Handle<JSReceiver> current =
     182             :         PrototypeIterator::GetCurrent<JSReceiver>(iter);
     183             :     Maybe<bool> result = Just(false);  // Dummy initialization.
     184     4292168 :     if (current->IsJSProxy()) {
     185      922196 :       result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current));
     186             :     } else {
     187             :       DCHECK(current->IsJSObject());
     188     1223888 :       result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current));
     189             :     }
     190     2146084 :     MAYBE_RETURN(result, Nothing<bool>());
     191     2145937 :     if (!result.FromJust()) break;  // |false| means "stop iterating".
     192             :     // Iterate through proxies but ignore access checks for the ALL_CAN_READ
     193             :     // case on API objects for OWN_ONLY keys handled in CollectOwnKeys.
     194     2145900 :     if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
     195             :       return Nothing<bool>();
     196             :     }
     197     2148858 :     if (!last_non_empty_prototype_.is_null() &&
     198             :         *last_non_empty_prototype_ == *current) {
     199             :       break;
     200             :     }
     201             :   }
     202             :   return Just(true);
     203             : }
     204             : 
     205           0 : bool KeyAccumulator::HasShadowingKeys() { return !shadowing_keys_.is_null(); }
     206             : 
     207    10001094 : bool KeyAccumulator::IsShadowed(Handle<Object> key) {
     208    10001094 :   if (!HasShadowingKeys() || skip_shadow_check_) return false;
     209       19854 :   return shadowing_keys_->Has(isolate_, key);
     210             : }
     211             : 
     212      109317 : void KeyAccumulator::AddShadowingKey(Object key) {
     213      218634 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     214      211352 :   AddShadowingKey(handle(key, isolate_));
     215             : }
     216      211478 : void KeyAccumulator::AddShadowingKey(Handle<Object> key) {
     217      211604 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     218      105676 :   if (shadowing_keys_.is_null()) {
     219        6588 :     shadowing_keys_ = ObjectHashSet::New(isolate_, 16);
     220             :   }
     221      105676 :   shadowing_keys_ = ObjectHashSet::Add(isolate(), shadowing_keys_, key);
     222             : }
     223             : 
     224             : namespace {
     225             : 
     226        4968 : void TrySettingEmptyEnumCache(JSReceiver object) {
     227        4968 :   Map map = object->map();
     228             :   DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
     229        5944 :   if (!map->OnlyHasSimpleProperties()) return;
     230        4334 :   if (map->IsJSProxyMap()) return;
     231        4334 :   if (map->NumberOfEnumerableProperties() > 0) return;
     232             :   DCHECK(object->IsJSObject());
     233        3992 :   map->SetEnumLength(0);
     234             : }
     235             : 
     236      101636 : bool CheckAndInitalizeEmptyEnumCache(JSReceiver object) {
     237      101636 :   if (object->map()->EnumLength() == kInvalidEnumCacheSentinel) {
     238        4968 :     TrySettingEmptyEnumCache(object);
     239             :   }
     240      101636 :   if (object->map()->EnumLength() != 0) return false;
     241             :   DCHECK(object->IsJSObject());
     242      100192 :   return !JSObject::cast(object)->HasEnumerableElements();
     243             : }
     244             : }  // namespace
     245             : 
     246     1386680 : void FastKeyAccumulator::Prepare() {
     247             :   DisallowHeapAllocation no_gc;
     248             :   // Directly go for the fast path for OWN_ONLY keys.
     249     2773360 :   if (mode_ == KeyCollectionMode::kOwnOnly) return;
     250             :   // Fully walk the prototype chain and find the last prototype with keys.
     251       54274 :   is_receiver_simple_enum_ = false;
     252       54274 :   has_empty_prototype_ = true;
     253             :   JSReceiver last_prototype;
     254      210184 :   for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
     255      101636 :        iter.Advance()) {
     256      101636 :     JSReceiver current = iter.GetCurrent<JSReceiver>();
     257      101636 :     bool has_no_properties = CheckAndInitalizeEmptyEnumCache(current);
     258      201783 :     if (has_no_properties) continue;
     259        1489 :     last_prototype = current;
     260        1489 :     has_empty_prototype_ = false;
     261             :   }
     262       54274 :   if (has_empty_prototype_) {
     263             :     is_receiver_simple_enum_ =
     264       96981 :         receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
     265       96981 :         !JSObject::cast(*receiver_)->HasEnumerableElements();
     266        1404 :   } else if (!last_prototype.is_null()) {
     267        2808 :     last_non_empty_prototype_ = handle(last_prototype, isolate_);
     268             :   }
     269             : }
     270             : 
     271             : namespace {
     272             : 
     273      174610 : Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
     274             :                                       Handle<FixedArray> array, int length) {
     275             :   DCHECK_LE(length, array->length());
     276      174610 :   if (array->length() == length) return array;
     277         276 :   return isolate->factory()->CopyFixedArrayUpTo(array, length);
     278             : }
     279             : 
     280             : // Initializes and directly returns the enume cache. Users of this function
     281             : // have to make sure to never directly leak the enum cache.
     282      222586 : Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
     283             :                                            Handle<JSObject> object) {
     284             :   Handle<Map> map(object->map(), isolate);
     285      445172 :   Handle<FixedArray> keys(map->instance_descriptors()->enum_cache()->keys(),
     286      445172 :                           isolate);
     287             : 
     288             :   // Check if the {map} has a valid enum length, which implies that it
     289             :   // must have a valid enum cache as well.
     290             :   int enum_length = map->EnumLength();
     291      222586 :   if (enum_length != kInvalidEnumCacheSentinel) {
     292             :     DCHECK(map->OnlyHasSimpleProperties());
     293             :     DCHECK_LE(enum_length, keys->length());
     294             :     DCHECK_EQ(enum_length, map->NumberOfEnumerableProperties());
     295      148467 :     isolate->counters()->enum_cache_hits()->Increment();
     296      148467 :     return ReduceFixedArrayTo(isolate, keys, enum_length);
     297             :   }
     298             : 
     299             :   // Determine the actual number of enumerable properties of the {map}.
     300       74119 :   enum_length = map->NumberOfEnumerableProperties();
     301             : 
     302             :   // Check if there's already a shared enum cache on the {map}s
     303             :   // DescriptorArray with sufficient number of entries.
     304       74119 :   if (enum_length <= keys->length()) {
     305       31944 :     if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
     306       26143 :     isolate->counters()->enum_cache_hits()->Increment();
     307       26143 :     return ReduceFixedArrayTo(isolate, keys, enum_length);
     308             :   }
     309             : 
     310             :   Handle<DescriptorArray> descriptors =
     311       95952 :       Handle<DescriptorArray>(map->instance_descriptors(), isolate);
     312       47976 :   isolate->counters()->enum_cache_misses()->Increment();
     313             :   int nod = map->NumberOfOwnDescriptors();
     314             : 
     315             :   // Create the keys array.
     316             :   int index = 0;
     317             :   bool fields_only = true;
     318       47976 :   keys = isolate->factory()->NewFixedArray(enum_length);
     319      351789 :   for (int i = 0; i < nod; i++) {
     320             :     DisallowHeapAllocation no_gc;
     321      303813 :     PropertyDetails details = descriptors->GetDetails(i);
     322      305604 :     if (details.IsDontEnum()) continue;
     323      302142 :     Object key = descriptors->GetKey(i);
     324      302142 :     if (key->IsSymbol()) continue;
     325      302022 :     keys->set(index, key);
     326      302022 :     if (details.location() != kField) fields_only = false;
     327      302022 :     index++;
     328             :   }
     329             :   DCHECK_EQ(index, keys->length());
     330             : 
     331             :   // Optionally also create the indices array.
     332             :   Handle<FixedArray> indices = isolate->factory()->empty_fixed_array();
     333       47976 :   if (fields_only) {
     334       29992 :     indices = isolate->factory()->NewFixedArray(enum_length);
     335             :     index = 0;
     336      262891 :     for (int i = 0; i < nod; i++) {
     337             :       DisallowHeapAllocation no_gc;
     338      232899 :       PropertyDetails details = descriptors->GetDetails(i);
     339      234320 :       if (details.IsDontEnum()) continue;
     340      231580 :       Object key = descriptors->GetKey(i);
     341      231580 :       if (key->IsSymbol()) continue;
     342             :       DCHECK_EQ(kData, details.kind());
     343             :       DCHECK_EQ(kField, details.location());
     344      231478 :       FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
     345      231478 :       indices->set(index, Smi::FromInt(field_index.GetLoadByFieldIndex()));
     346      231478 :       index++;
     347             :     }
     348             :     DCHECK_EQ(index, indices->length());
     349             :   }
     350             : 
     351             :   DescriptorArray::InitializeOrChangeEnumCache(descriptors, isolate, keys,
     352       47976 :                                                indices);
     353       95854 :   if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
     354             : 
     355       47976 :   return keys;
     356             : }
     357             : 
     358             : template <bool fast_properties>
     359      141835 : MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate,
     360             :                                                Handle<JSObject> object,
     361             :                                                GetKeysConversion convert,
     362             :                                                bool skip_indices) {
     363             :   Handle<FixedArray> keys;
     364      141835 :   ElementsAccessor* accessor = object->GetElementsAccessor();
     365             :   if (fast_properties) {
     366      135486 :     keys = GetFastEnumPropertyKeys(isolate, object);
     367             :   } else {
     368             :     // TODO(cbruni): preallocate big enough array to also hold elements.
     369        6349 :     keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate, object);
     370             :   }
     371             : 
     372             :   MaybeHandle<FixedArray> result;
     373      141835 :   if (skip_indices) {
     374             :     result = keys;
     375             :   } else {
     376      141751 :     result =
     377             :         accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE);
     378             :   }
     379             : 
     380      141835 :   if (FLAG_trace_for_in_enumerate) {
     381           0 :     PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n",
     382           0 :            keys->length(), result.ToHandleChecked()->length() - keys->length());
     383             :   }
     384      141835 :   return result;
     385             : }
     386             : 
     387             : }  // namespace
     388             : 
     389     1383840 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(
     390             :     GetKeysConversion keys_conversion) {
     391     1383840 :   if (filter_ == ENUMERABLE_STRINGS) {
     392             :     Handle<FixedArray> keys;
     393      471406 :     if (GetKeysFast(keys_conversion).ToHandle(&keys)) {
     394      195169 :       return keys;
     395             :     }
     396       40534 :     if (isolate_->has_pending_exception()) return MaybeHandle<FixedArray>();
     397             :   }
     398             : 
     399     1188671 :   return GetKeysSlow(keys_conversion);
     400             : }
     401             : 
     402      235703 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
     403             :     GetKeysConversion keys_conversion) {
     404      235703 :   bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly;
     405      235703 :   Map map = receiver_->map();
     406      470002 :   if (!own_only || map->IsCustomElementsReceiverMap()) {
     407       40534 :     return MaybeHandle<FixedArray>();
     408             :   }
     409             : 
     410             :   // From this point on we are certain to only collect own keys.
     411             :   DCHECK(receiver_->IsJSObject());
     412      195169 :   Handle<JSObject> object = Handle<JSObject>::cast(receiver_);
     413             : 
     414             :   // Do not try to use the enum-cache for dict-mode objects.
     415      195169 :   if (map->is_dictionary_map()) {
     416             :     return GetOwnKeysWithElements<false>(isolate_, object, keys_conversion,
     417        6349 :                                          skip_indices_);
     418             :   }
     419             :   int enum_length = receiver_->map()->EnumLength();
     420      188820 :   if (enum_length == kInvalidEnumCacheSentinel) {
     421             :     Handle<FixedArray> keys;
     422             :     // Try initializing the enum cache and return own properties.
     423      110882 :     if (GetOwnKeysWithUninitializedEnumCache().ToHandle(&keys)) {
     424       53334 :       if (FLAG_trace_for_in_enumerate) {
     425             :         PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n",
     426           0 :                keys->length());
     427             :       }
     428             :       is_receiver_simple_enum_ =
     429       53334 :           object->map()->EnumLength() != kInvalidEnumCacheSentinel;
     430       53334 :       return keys;
     431             :     }
     432             :   }
     433             :   // The properties-only case failed because there were probably elements on the
     434             :   // receiver.
     435             :   return GetOwnKeysWithElements<true>(isolate_, object, keys_conversion,
     436      135486 :                                       skip_indices_);
     437             : }
     438             : 
     439             : MaybeHandle<FixedArray>
     440       55441 : FastKeyAccumulator::GetOwnKeysWithUninitializedEnumCache() {
     441       55441 :   Handle<JSObject> object = Handle<JSObject>::cast(receiver_);
     442             :   // Uninitalized enum cache
     443       55441 :   Map map = object->map();
     444      110882 :   if (object->elements()->length() != 0) {
     445             :     // Assume that there are elements.
     446        2107 :     return MaybeHandle<FixedArray>();
     447             :   }
     448             :   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
     449       53334 :   if (number_of_own_descriptors == 0) {
     450        4249 :     map->SetEnumLength(0);
     451        8498 :     return isolate_->factory()->empty_fixed_array();
     452             :   }
     453             :   // We have no elements but possibly enumerable property keys, hence we can
     454             :   // directly initialize the enum cache.
     455       49085 :   Handle<FixedArray> keys = GetFastEnumPropertyKeys(isolate_, object);
     456       49085 :   if (is_for_in_) return keys;
     457             :   // Do not leak the enum cache as it might end up as an elements backing store.
     458       44420 :   return isolate_->factory()->CopyFixedArray(keys);
     459             : }
     460             : 
     461     1188671 : MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
     462             :     GetKeysConversion keys_conversion) {
     463     1188671 :   KeyAccumulator accumulator(isolate_, mode_, filter_);
     464     1188671 :   accumulator.set_is_for_in(is_for_in_);
     465     1188671 :   accumulator.set_skip_indices(skip_indices_);
     466             :   accumulator.set_last_non_empty_prototype(last_non_empty_prototype_);
     467             : 
     468     1188671 :   MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_),
     469             :                MaybeHandle<FixedArray>());
     470     1170395 :   return accumulator.GetKeys(keys_conversion);
     471             : }
     472             : 
     473             : namespace {
     474             : 
     475             : enum IndexedOrNamed { kIndexed, kNamed };
     476             : 
     477          60 : void FilterForEnumerableProperties(Handle<JSReceiver> receiver,
     478             :                                    Handle<JSObject> object,
     479             :                                    Handle<InterceptorInfo> interceptor,
     480         156 :                                    KeyAccumulator* accumulator,
     481             :                                    Handle<JSObject> result,
     482             :                                    IndexedOrNamed type) {
     483             :   DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements());
     484          60 :   ElementsAccessor* accessor = result->GetElementsAccessor();
     485             : 
     486         180 :   uint32_t length = accessor->GetCapacity(*result, result->elements());
     487         282 :   for (uint32_t i = 0; i < length; i++) {
     488         510 :     if (!accessor->HasEntry(*result, i)) continue;
     489             : 
     490             :     // args are invalid after args.Call(), create a new one in every iteration.
     491             :     PropertyCallbackArguments args(accumulator->isolate(), interceptor->data(),
     492         468 :                                    *receiver, *object, kDontThrow);
     493             : 
     494         156 :     Handle<Object> element = accessor->Get(result, i);
     495             :     Handle<Object> attributes;
     496         156 :     if (type == kIndexed) {
     497             :       uint32_t number;
     498          84 :       CHECK(element->ToUint32(&number));
     499          84 :       attributes = args.CallIndexedQuery(interceptor, number);
     500             :     } else {
     501         144 :       CHECK(element->IsName());
     502             :       attributes =
     503          72 :           args.CallNamedQuery(interceptor, Handle<Name>::cast(element));
     504             :     }
     505             : 
     506         156 :     if (!attributes.is_null()) {
     507             :       int32_t value;
     508         144 :       CHECK(attributes->ToInt32(&value));
     509         144 :       if ((value & DONT_ENUM) == 0) {
     510          48 :         accumulator->AddKey(element, DO_NOT_CONVERT);
     511             :       }
     512             :     }
     513             :   }
     514          60 : }
     515             : 
     516             : // Returns |true| on success, |nothing| on exception.
     517         475 : Maybe<bool> CollectInterceptorKeysInternal(Handle<JSReceiver> receiver,
     518             :                                            Handle<JSObject> object,
     519             :                                            Handle<InterceptorInfo> interceptor,
     520         844 :                                            KeyAccumulator* accumulator,
     521             :                                            IndexedOrNamed type) {
     522             :   Isolate* isolate = accumulator->isolate();
     523             :   PropertyCallbackArguments enum_args(isolate, interceptor->data(), *receiver,
     524         950 :                                       *object, kDontThrow);
     525             : 
     526             :   Handle<JSObject> result;
     527         950 :   if (!interceptor->enumerator()->IsUndefined(isolate)) {
     528         475 :     if (type == kIndexed) {
     529         235 :       result = enum_args.CallIndexedEnumerator(interceptor);
     530             :     } else {
     531             :       DCHECK_EQ(type, kNamed);
     532         240 :       result = enum_args.CallNamedEnumerator(interceptor);
     533             :     }
     534             :   }
     535         475 :   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
     536         445 :   if (result.is_null()) return Just(true);
     537             : 
     538        1107 :   if ((accumulator->filter() & ONLY_ENUMERABLE) &&
     539         607 :       !interceptor->query()->IsUndefined(isolate)) {
     540             :     FilterForEnumerableProperties(receiver, object, interceptor, accumulator,
     541          60 :                                   result, type);
     542             :   } else {
     543             :     accumulator->AddKeys(
     544         309 :         result, type == kIndexed ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
     545             :   }
     546             :   return Just(true);
     547             : }
     548             : 
     549     2451814 : Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver,
     550             :                                    Handle<JSObject> object,
     551     2452249 :                                    KeyAccumulator* accumulator,
     552             :                                    IndexedOrNamed type) {
     553             :   Isolate* isolate = accumulator->isolate();
     554     2451814 :   if (type == kIndexed) {
     555     1227981 :     if (!object->HasIndexedInterceptor()) return Just(true);
     556             :   } else {
     557     1223833 :     if (!object->HasNamedInterceptor()) return Just(true);
     558             :   }
     559             :   Handle<InterceptorInfo> interceptor(type == kIndexed
     560         865 :                                           ? object->GetIndexedInterceptor()
     561         655 :                                           : object->GetNamedInterceptor(),
     562        1090 :                                       isolate);
     563        1305 :   if ((accumulator->filter() & ONLY_ALL_CAN_READ) &&
     564         435 :       !interceptor->all_can_read()) {
     565             :     return Just(true);
     566             :   }
     567             :   return CollectInterceptorKeysInternal(receiver, object, interceptor,
     568         435 :                                         accumulator, type);
     569             : }
     570             : 
     571             : }  // namespace
     572             : 
     573     1228549 : Maybe<bool> KeyAccumulator::CollectOwnElementIndices(
     574             :     Handle<JSReceiver> receiver, Handle<JSObject> object) {
     575     1228549 :   if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true);
     576             : 
     577     1227981 :   ElementsAccessor* accessor = object->GetElementsAccessor();
     578     1227981 :   accessor->CollectElementIndices(object, this);
     579             : 
     580     1227981 :   return CollectInterceptorKeys(receiver, object, this, kIndexed);
     581             : }
     582             : 
     583             : namespace {
     584             : 
     585             : template <bool skip_symbols>
     586     1147384 : int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
     587     2186592 :                                     KeyAccumulator* keys,
     588             :                                     Handle<DescriptorArray> descs,
     589             :                                     int start_index, int limit) {
     590             :   int first_skipped = -1;
     591             :   PropertyFilter filter = keys->filter();
     592             :   KeyCollectionMode mode = keys->mode();
     593     1210962 :   for (int i = start_index; i < limit; i++) {
     594             :     bool is_shadowing_key = false;
     595     1210962 :     PropertyDetails details = descs->GetDetails(i);
     596             : 
     597     1210962 :     if ((details.attributes() & filter) != 0) {
     598          12 :       if (mode == KeyCollectionMode::kIncludePrototypes) {
     599             :         is_shadowing_key = true;
     600             :       } else {
     601      183821 :         continue;
     602             :       }
     603             :     }
     604             : 
     605     1210950 :     if (filter & ONLY_ALL_CAN_READ) {
     606          18 :       if (details.kind() != kAccessor) continue;
     607           6 :       Object accessors = descs->GetStrongValue(i);
     608           6 :       if (!accessors->IsAccessorInfo()) continue;
     609           6 :       if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
     610             :     }
     611             : 
     612     1210944 :     Name key = descs->GetKey(i);
     613     1210944 :     if (skip_symbols == key->IsSymbol()) {
     614      171736 :       if (first_skipped == -1) first_skipped = i;
     615             :       continue;
     616             :     }
     617     1039208 :     if (key->FilterKey(keys->filter())) continue;
     618             : 
     619     1027141 :     if (is_shadowing_key) {
     620           0 :       keys->AddShadowingKey(key);
     621             :     } else {
     622     1027141 :       keys->AddKey(key, DO_NOT_CONVERT);
     623             :     }
     624             :   }
     625     1147384 :   return first_skipped;
     626             : }
     627             : 
     628             : template <class T>
     629       43149 : Handle<FixedArray> GetOwnEnumPropertyDictionaryKeys(Isolate* isolate,
     630             :                                                     KeyCollectionMode mode,
     631             :                                                     KeyAccumulator* accumulator,
     632             :                                                     Handle<JSObject> object,
     633             :                                                     T raw_dictionary) {
     634             :   Handle<T> dictionary(raw_dictionary, isolate);
     635       43149 :   if (dictionary->NumberOfElements() == 0) {
     636             :     return isolate->factory()->empty_fixed_array();
     637             :   }
     638       42875 :   int length = dictionary->NumberOfEnumerableProperties();
     639       42875 :   Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
     640       42875 :   T::CopyEnumKeysTo(isolate, dictionary, storage, mode, accumulator);
     641       42875 :   return storage;
     642             : }
     643             : }  // namespace
     644             : 
     645     1223887 : Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver,
     646         243 :                                                     Handle<JSObject> object) {
     647     1223887 :   if (filter_ == ENUMERABLE_STRINGS) {
     648             :     Handle<FixedArray> enum_keys;
     649       72106 :     if (object->HasFastProperties()) {
     650       35504 :       enum_keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, object);
     651             :       // If the number of properties equals the length of enumerable properties
     652             :       // we do not have to filter out non-enumerable ones
     653       35504 :       Map map = object->map();
     654             :       int nof_descriptors = map->NumberOfOwnDescriptors();
     655       35504 :       if (enum_keys->length() != nof_descriptors) {
     656             :         Handle<DescriptorArray> descs =
     657        8889 :             Handle<DescriptorArray>(map->instance_descriptors(), isolate_);
     658      108687 :         for (int i = 0; i < nof_descriptors; i++) {
     659       99798 :           PropertyDetails details = descs->GetDetails(i);
     660      103267 :           if (!details.IsDontEnum()) continue;
     661       96329 :           Object key = descs->GetKey(i);
     662       96329 :           this->AddShadowingKey(key);
     663             :         }
     664             :       }
     665       73204 :     } else if (object->IsJSGlobalObject()) {
     666             :       enum_keys = GetOwnEnumPropertyDictionaryKeys(
     667             :           isolate_, mode_, this, object,
     668       36269 :           JSGlobalObject::cast(*object)->global_dictionary());
     669             :     } else {
     670             :       enum_keys = GetOwnEnumPropertyDictionaryKeys(
     671         333 :           isolate_, mode_, this, object, object->property_dictionary());
     672             :     }
     673      144212 :     if (object->IsJSModuleNamespace()) {
     674             :       // Simulate [[GetOwnProperty]] for establishing enumerability, which
     675             :       // throws for uninitialized exports.
     676         315 :       for (int i = 0, n = enum_keys->length(); i < n; ++i) {
     677         243 :         Handle<String> key(String::cast(enum_keys->get(i)), isolate_);
     678         243 :         if (Handle<JSModuleNamespace>::cast(object)
     679         729 :                 ->GetExport(isolate(), key)
     680         486 :                 .is_null()) {
     681          54 :           return Nothing<bool>();
     682             :         }
     683             :       }
     684             :     }
     685       72052 :     AddKeys(enum_keys, DO_NOT_CONVERT);
     686             :   } else {
     687     1151781 :     if (object->HasFastProperties()) {
     688             :       int limit = object->map()->NumberOfOwnDescriptors();
     689             :       Handle<DescriptorArray> descs(object->map()->instance_descriptors(),
     690     3385044 :                                     isolate_);
     691             :       // First collect the strings,
     692             :       int first_symbol =
     693     1128348 :           CollectOwnPropertyNamesInternal<true>(object, this, descs, 0, limit);
     694             :       // then the symbols.
     695     1128348 :       if (first_symbol != -1) {
     696             :         CollectOwnPropertyNamesInternal<false>(object, this, descs,
     697       19036 :                                                first_symbol, limit);
     698             :       }
     699       46866 :     } else if (object->IsJSGlobalObject()) {
     700             :       GlobalDictionary::CollectKeysTo(
     701             :           handle(JSGlobalObject::cast(*object)->global_dictionary(), isolate_),
     702       68013 :           this);
     703             :     } else {
     704             :       NameDictionary::CollectKeysTo(
     705        2286 :           handle(object->property_dictionary(), isolate_), this);
     706             :     }
     707             :   }
     708             :   // Add the property keys from the interceptor.
     709     1223833 :   return CollectInterceptorKeys(receiver, object, this, kNamed);
     710             : }
     711             : 
     712          20 : Maybe<bool> KeyAccumulator::CollectAccessCheckInterceptorKeys(
     713             :     Handle<AccessCheckInfo> access_check_info, Handle<JSReceiver> receiver,
     714             :     Handle<JSObject> object) {
     715          20 :   if (!skip_indices_) {
     716          60 :     MAYBE_RETURN((CollectInterceptorKeysInternal(
     717             :                      receiver, object,
     718             :                      handle(InterceptorInfo::cast(
     719             :                                 access_check_info->indexed_interceptor()),
     720             :                             isolate_),
     721             :                      this, kIndexed)),
     722             :                  Nothing<bool>());
     723             :   }
     724          60 :   MAYBE_RETURN(
     725             :       (CollectInterceptorKeysInternal(
     726             :           receiver, object,
     727             :           handle(InterceptorInfo::cast(access_check_info->named_interceptor()),
     728             :                  isolate_),
     729             :           this, kNamed)),
     730             :       Nothing<bool>());
     731             :   return Just(true);
     732             : }
     733             : 
     734             : // Returns |true| on success, |false| if prototype walking should be stopped,
     735             : // |nothing| if an exception was thrown.
     736     1223888 : Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
     737             :                                            Handle<JSObject> object) {
     738             :   // Check access rights if required.
     739     2447870 :   if (object->IsAccessCheckNeeded() &&
     740         188 :       !isolate_->MayAccess(handle(isolate_->context(), isolate_), object)) {
     741             :     // The cross-origin spec says that [[Enumerate]] shall return an empty
     742             :     // iterator when it doesn't have access...
     743          69 :     if (mode_ == KeyCollectionMode::kIncludePrototypes) {
     744             :       return Just(false);
     745             :     }
     746             :     // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
     747             :     DCHECK_EQ(KeyCollectionMode::kOwnOnly, mode_);
     748             :     Handle<AccessCheckInfo> access_check_info;
     749             :     {
     750             :       DisallowHeapAllocation no_gc;
     751          52 :       AccessCheckInfo maybe_info = AccessCheckInfo::Get(isolate_, object);
     752          52 :       if (!maybe_info.is_null()) {
     753          42 :         access_check_info = handle(maybe_info, isolate_);
     754             :       }
     755             :     }
     756             :     // We always have both kinds of interceptors or none.
     757         146 :     if (!access_check_info.is_null() &&
     758          94 :         access_check_info->named_interceptor() != Object()) {
     759          20 :       MAYBE_RETURN(CollectAccessCheckInterceptorKeys(access_check_info,
     760             :                                                      receiver, object),
     761             :                    Nothing<bool>());
     762             :       return Just(false);
     763             :     }
     764          32 :     filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ);
     765             :   }
     766     1223851 :   MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>());
     767     1223839 :   MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>());
     768             :   return Just(true);
     769             : }
     770             : 
     771             : // static
     772       44562 : Handle<FixedArray> KeyAccumulator::GetOwnEnumPropertyKeys(
     773             :     Isolate* isolate, Handle<JSObject> object) {
     774       44562 :   if (object->HasFastProperties()) {
     775       38015 :     return GetFastEnumPropertyKeys(isolate, object);
     776       13094 :   } else if (object->IsJSGlobalObject()) {
     777             :     return GetOwnEnumPropertyDictionaryKeys(
     778             :         isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
     779          18 :         JSGlobalObject::cast(*object)->global_dictionary());
     780             :   } else {
     781             :     return GetOwnEnumPropertyDictionaryKeys(
     782             :         isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
     783        6529 :         object->property_dictionary());
     784             :   }
     785             : }
     786             : 
     787             : namespace {
     788             : 
     789             : class NameComparator {
     790             :  public:
     791             :   explicit NameComparator(Isolate* isolate) : isolate_(isolate) {}
     792             : 
     793             :   bool operator()(uint32_t hash1, uint32_t hash2, const Handle<Name>& key1,
     794             :                   const Handle<Name>& key2) const {
     795         606 :     return Name::Equals(isolate_, key1, key2);
     796             :   }
     797             : 
     798             :  private:
     799             :   Isolate* isolate_;
     800             : };
     801             : 
     802             : }  // namespace
     803             : 
     804             : // ES6 9.5.12
     805             : // Returns |true| on success, |nothing| in case of exception.
     806      942029 : Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver,
     807             :                                                   Handle<JSProxy> proxy) {
     808     1884265 :   STACK_CHECK(isolate_, Nothing<bool>());
     809             :   // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
     810     2826060 :   Handle<Object> handler(proxy->handler(), isolate_);
     811             :   // 2. If handler is null, throw a TypeError exception.
     812             :   // 3. Assert: Type(handler) is Object.
     813     1884040 :   if (proxy->IsRevoked()) {
     814             :     isolate_->Throw(*isolate_->factory()->NewTypeError(
     815          54 :         MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string()));
     816             :     return Nothing<bool>();
     817             :   }
     818             :   // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
     819     2826006 :   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate_);
     820             :   // 5. Let trap be ? GetMethod(handler, "ownKeys").
     821             :   Handle<Object> trap;
     822     2826006 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     823             :       isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
     824             :                                         isolate_->factory()->ownKeys_string()),
     825             :       Nothing<bool>());
     826             :   // 6. If trap is undefined, then
     827     2825898 :   if (trap->IsUndefined(isolate_)) {
     828             :     // 6a. Return target.[[OwnPropertyKeys]]().
     829      934709 :     return CollectOwnJSProxyTargetKeys(proxy, target);
     830             :   }
     831             :   // 7. Let trapResultArray be Call(trap, handler, «target»).
     832             :   Handle<Object> trap_result_array;
     833             :   Handle<Object> args[] = {target};
     834       14514 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     835             :       isolate_, trap_result_array,
     836             :       Execution::Call(isolate_, trap, handler, arraysize(args), args),
     837             :       Nothing<bool>());
     838             :   // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
     839             :   //    «String, Symbol»).
     840             :   Handle<FixedArray> trap_result;
     841        2322 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     842             :       isolate_, trap_result,
     843             :       Object::CreateListFromArrayLike(isolate_, trap_result_array,
     844             :                                       ElementTypes::kStringAndSymbol),
     845             :       Nothing<bool>());
     846             :   // 9. Let extensibleTarget be ? IsExtensible(target).
     847        1044 :   Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
     848        1044 :   MAYBE_RETURN(maybe_extensible, Nothing<bool>());
     849             :   bool extensible_target = maybe_extensible.FromJust();
     850             :   // 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
     851             :   Handle<FixedArray> target_keys;
     852        2088 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, target_keys,
     853             :                                    JSReceiver::OwnPropertyKeys(target),
     854             :                                    Nothing<bool>());
     855             :   // 11. (Assert)
     856             :   // 12. Let targetConfigurableKeys be an empty List.
     857             :   // To save memory, we're re-using target_keys and will modify it in-place.
     858             :   Handle<FixedArray> target_configurable_keys = target_keys;
     859             :   // 13. Let targetNonconfigurableKeys be an empty List.
     860             :   Handle<FixedArray> target_nonconfigurable_keys =
     861        1044 :       isolate_->factory()->NewFixedArray(target_keys->length());
     862             :   int nonconfigurable_keys_length = 0;
     863             :   // 14. Repeat, for each element key of targetKeys:
     864        3852 :   for (int i = 0; i < target_keys->length(); ++i) {
     865             :     // 14a. Let desc be ? target.[[GetOwnProperty]](key).
     866             :     PropertyDescriptor desc;
     867             :     Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
     868        1764 :         isolate_, target, handle(target_keys->get(i), isolate_), &desc);
     869         882 :     MAYBE_RETURN(found, Nothing<bool>());
     870             :     // 14b. If desc is not undefined and desc.[[Configurable]] is false, then
     871        1764 :     if (found.FromJust() && !desc.configurable()) {
     872             :       // 14b i. Append key as an element of targetNonconfigurableKeys.
     873             :       target_nonconfigurable_keys->set(nonconfigurable_keys_length,
     874         306 :                                        target_keys->get(i));
     875         306 :       nonconfigurable_keys_length++;
     876             :       // The key was moved, null it out in the original list.
     877         306 :       target_keys->set(i, Smi::kZero);
     878             :     } else {
     879             :       // 14c. Else,
     880             :       // 14c i. Append key as an element of targetConfigurableKeys.
     881             :       // (No-op, just keep it in |target_keys|.)
     882             :     }
     883             :   }
     884             :   // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty,
     885             :   //     then:
     886        1044 :   if (extensible_target && nonconfigurable_keys_length == 0) {
     887             :     // 15a. Return trapResult.
     888         837 :     return AddKeysFromJSProxy(proxy, trap_result);
     889             :   }
     890             :   // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
     891         414 :   Zone set_zone(isolate_->allocator(), ZONE_NAME);
     892             :   ZoneAllocationPolicy alloc(&set_zone);
     893             :   const int kPresent = 1;
     894             :   const int kGone = 0;
     895             :   base::TemplateHashMapImpl<Handle<Name>, int, NameComparator,
     896             :                             ZoneAllocationPolicy>
     897             :       unchecked_result_keys(ZoneHashMap::kDefaultHashMapCapacity,
     898         207 :                             NameComparator(isolate_), alloc);
     899             :   int unchecked_result_keys_size = 0;
     900        2034 :   for (int i = 0; i < trap_result->length(); ++i) {
     901         810 :     Handle<Name> key(Name::cast(trap_result->get(i)), isolate_);
     902        1620 :     auto entry = unchecked_result_keys.LookupOrInsert(key, key->Hash(), alloc);
     903         810 :     if (entry->value != kPresent) {
     904         639 :       entry->value = kPresent;
     905         639 :       unchecked_result_keys_size++;
     906             :     }
     907             :   }
     908             :   // 17. Repeat, for each key that is an element of targetNonconfigurableKeys:
     909         297 :   for (int i = 0; i < nonconfigurable_keys_length; ++i) {
     910             :     Object raw_key = target_nonconfigurable_keys->get(i);
     911         306 :     Handle<Name> key(Name::cast(raw_key), isolate_);
     912             :     // 17a. If key is not an element of uncheckedResultKeys, throw a
     913             :     //      TypeError exception.
     914         612 :     auto found = unchecked_result_keys.Lookup(key, key->Hash());
     915         306 :     if (found == nullptr || found->value == kGone) {
     916             :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     917          18 :           MessageTemplate::kProxyOwnKeysMissing, key));
     918           9 :       return Nothing<bool>();
     919             :     }
     920             :     // 17b. Remove key from uncheckedResultKeys.
     921         297 :     found->value = kGone;
     922         297 :     unchecked_result_keys_size--;
     923             :   }
     924             :   // 18. If extensibleTarget is true, return trapResult.
     925         198 :   if (extensible_target) {
     926          99 :     return AddKeysFromJSProxy(proxy, trap_result);
     927             :   }
     928             :   // 19. Repeat, for each key that is an element of targetConfigurableKeys:
     929         675 :   for (int i = 0; i < target_configurable_keys->length(); ++i) {
     930         297 :     Object raw_key = target_configurable_keys->get(i);
     931         477 :     if (raw_key->IsSmi()) continue;  // Zapped entry, was nonconfigurable.
     932         117 :     Handle<Name> key(Name::cast(raw_key), isolate_);
     933             :     // 19a. If key is not an element of uncheckedResultKeys, throw a
     934             :     //      TypeError exception.
     935         234 :     auto found = unchecked_result_keys.Lookup(key, key->Hash());
     936         117 :     if (found == nullptr || found->value == kGone) {
     937             :       isolate_->Throw(*isolate_->factory()->NewTypeError(
     938          18 :           MessageTemplate::kProxyOwnKeysMissing, key));
     939           9 :       return Nothing<bool>();
     940             :     }
     941             :     // 19b. Remove key from uncheckedResultKeys.
     942         108 :     found->value = kGone;
     943         108 :     unchecked_result_keys_size--;
     944             :   }
     945             :   // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
     946          90 :   if (unchecked_result_keys_size != 0) {
     947             :     DCHECK_GT(unchecked_result_keys_size, 0);
     948             :     isolate_->Throw(*isolate_->factory()->NewTypeError(
     949          18 :         MessageTemplate::kProxyOwnKeysNonExtensible));
     950             :     return Nothing<bool>();
     951             :   }
     952             :   // 21. Return trapResult.
     953          81 :   return AddKeysFromJSProxy(proxy, trap_result);
     954             : }
     955             : 
     956      934709 : Maybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys(
     957             :     Handle<JSProxy> proxy, Handle<JSReceiver> target) {
     958             :   // TODO(cbruni): avoid creating another KeyAccumulator
     959             :   Handle<FixedArray> keys;
     960     1869418 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     961             :       isolate_, keys,
     962             :       KeyAccumulator::GetKeys(
     963             :           target, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
     964             :           GetKeysConversion::kConvertToString, is_for_in_, skip_indices_),
     965             :       Nothing<bool>());
     966      922910 :   Maybe<bool> result = AddKeysFromJSProxy(proxy, keys);
     967      922910 :   return result;
     968             : }
     969             : 
     970             : }  // namespace internal
     971      183867 : }  // namespace v8

Generated by: LCOV version 1.10