LCOV - code coverage report
Current view: top level - src/objects - ordered-hash-table.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 370 425 87.1 %
Date: 2019-01-20 Functions: 76 96 79.2 %

          Line data    Source code
       1             : // Copyright 2018 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/objects/ordered-hash-table.h"
       6             : 
       7             : #include "src/isolate.h"
       8             : #include "src/objects-inl.h"
       9             : #include "src/objects/js-collection-inl.h"
      10             : #include "src/objects/ordered-hash-table-inl.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : 
      15             : template <class Derived, int entrysize>
      16      841175 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Allocate(
      17             :     Isolate* isolate, int capacity, PretenureFlag pretenure) {
      18             :   // Capacity must be a power of two, since we depend on being able
      19             :   // to divide and multiple by 2 (kLoadFactor) to derive capacity
      20             :   // from number of buckets. If we decide to change kLoadFactor
      21             :   // to something other than 2, capacity should be stored as another
      22             :   // field of this object.
      23      841175 :   capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
      24      841176 :   if (capacity > MaxCapacity()) {
      25           0 :     isolate->heap()->FatalProcessOutOfMemory("invalid table size");
      26             :   }
      27      841176 :   int num_buckets = capacity / kLoadFactor;
      28             :   Handle<FixedArray> backing_store = isolate->factory()->NewFixedArrayWithMap(
      29             :       Derived::GetMapRootIndex(),
      30      841176 :       HashTableStartIndex() + num_buckets + (capacity * kEntrySize), pretenure);
      31      841176 :   Handle<Derived> table = Handle<Derived>::cast(backing_store);
      32    26133926 :   for (int i = 0; i < num_buckets; ++i) {
      33             :     table->set(HashTableStartIndex() + i, Smi::FromInt(kNotFound));
      34             :   }
      35             :   table->SetNumberOfBuckets(num_buckets);
      36             :   table->SetNumberOfElements(0);
      37             :   table->SetNumberOfDeletedElements(0);
      38      841176 :   return table;
      39             : }
      40             : 
      41             : template <class Derived, int entrysize>
      42    10183501 : Handle<Derived> OrderedHashTable<Derived, entrysize>::EnsureGrowable(
      43             :     Isolate* isolate, Handle<Derived> table) {
      44             :   DCHECK(!table->IsObsolete());
      45             : 
      46    10183501 :   int nof = table->NumberOfElements();
      47    10183501 :   int nod = table->NumberOfDeletedElements();
      48    20367002 :   int capacity = table->Capacity();
      49    10183501 :   if ((nof + nod) < capacity) return table;
      50             :   // Don't need to grow if we can simply clear out deleted entries instead.
      51             :   // Note that we can't compact in place, though, so we always allocate
      52             :   // a new table.
      53             :   return Derived::Rehash(isolate, table,
      54      349008 :                          (nod < (capacity >> 1)) ? capacity << 1 : capacity);
      55             : }
      56             : 
      57             : template <class Derived, int entrysize>
      58      162740 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Shrink(
      59             :     Isolate* isolate, Handle<Derived> table) {
      60             :   DCHECK(!table->IsObsolete());
      61             : 
      62      162740 :   int nof = table->NumberOfElements();
      63      325480 :   int capacity = table->Capacity();
      64      162740 :   if (nof >= (capacity >> 2)) return table;
      65          35 :   return Derived::Rehash(isolate, table, capacity / 2);
      66             : }
      67             : 
      68             : template <class Derived, int entrysize>
      69         254 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Clear(
      70             :     Isolate* isolate, Handle<Derived> table) {
      71             :   DCHECK(!table->IsObsolete());
      72             : 
      73             :   Handle<Derived> new_table = Allocate(
      74         254 :       isolate, kMinCapacity, Heap::InNewSpace(*table) ? NOT_TENURED : TENURED);
      75             : 
      76         508 :   table->SetNextTable(*new_table);
      77             :   table->SetNumberOfDeletedElements(kClearedTableSentinel);
      78             : 
      79         254 :   return new_table;
      80             : }
      81             : 
      82             : template <class Derived, int entrysize>
      83     4924595 : bool OrderedHashTable<Derived, entrysize>::HasKey(Isolate* isolate,
      84             :                                                   Derived table, Object key) {
      85             :   DCHECK_IMPLIES(entrysize == 1, table->IsOrderedHashSet());
      86             :   DCHECK_IMPLIES(entrysize == 2, table->IsOrderedHashMap());
      87             :   DisallowHeapAllocation no_gc;
      88     4924595 :   int entry = table->FindEntry(isolate, key);
      89     4924595 :   return entry != kNotFound;
      90             : }
      91             : 
      92             : template <class Derived, int entrysize>
      93     4924675 : int OrderedHashTable<Derived, entrysize>::FindEntry(Isolate* isolate,
      94             :                                                     Object key) {
      95             :   int entry;
      96             :   // This special cases for Smi, so that we avoid the HandleScope
      97             :   // creation below.
      98     4924675 :   if (key->IsSmi()) {
      99     4924335 :     uint32_t hash = ComputeUnseededHash(Smi::ToInt(key));
     100     4924335 :     entry = HashToEntry(hash & Smi::kMaxValue);
     101             :   } else {
     102             :     HandleScope scope(isolate);
     103         340 :     Object hash = key->GetHash();
     104             :     // If the object does not have an identity hash, it was never used as a key
     105         340 :     if (hash->IsUndefined(isolate)) return kNotFound;
     106         340 :     entry = HashToEntry(Smi::ToInt(hash));
     107             :   }
     108             : 
     109             :   // Walk the chain in the bucket to find the key.
     110     8718110 :   while (entry != kNotFound) {
     111     8717870 :     Object candidate_key = KeyAt(entry);
     112     8717870 :     if (candidate_key->SameValueZero(key)) break;
     113     3793435 :     entry = NextChainEntry(entry);
     114             :   }
     115             : 
     116     4924675 :   return entry;
     117             : }
     118             : 
     119     9997664 : Handle<OrderedHashSet> OrderedHashSet::Add(Isolate* isolate,
     120             :                                            Handle<OrderedHashSet> table,
     121             :                                            Handle<Object> key) {
     122    19995328 :   int hash = key->GetOrCreateHash(isolate)->value();
     123     9997664 :   int entry = table->HashToEntry(hash);
     124             :   // Walk the chain of the bucket and try finding the key.
     125    33721419 :   while (entry != kNotFound) {
     126    13726679 :     Object candidate_key = table->KeyAt(entry);
     127             :     // Do not add if we have the key already
     128    13726679 :     if (candidate_key->SameValueZero(*key)) return table;
     129    13726091 :     entry = table->NextChainEntry(entry);
     130             :   }
     131             : 
     132     9997076 :   table = OrderedHashSet::EnsureGrowable(isolate, table);
     133             :   // Read the existing bucket values.
     134    19994152 :   int bucket = table->HashToBucket(hash);
     135     9997076 :   int previous_entry = table->HashToEntry(hash);
     136     9997076 :   int nof = table->NumberOfElements();
     137             :   // Insert a new entry at the end,
     138     9997076 :   int new_entry = nof + table->NumberOfDeletedElements();
     139    19994152 :   int new_index = table->EntryToIndex(new_entry);
     140     9997076 :   table->set(new_index, *key);
     141             :   table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
     142             :   // and point the bucket to the new entry.
     143             :   table->set(HashTableStartIndex() + bucket, Smi::FromInt(new_entry));
     144     9997076 :   table->SetNumberOfElements(nof + 1);
     145     9997076 :   return table;
     146             : }
     147             : 
     148      249782 : Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
     149             :     Isolate* isolate, Handle<OrderedHashSet> table, GetKeysConversion convert) {
     150      249782 :   int length = table->NumberOfElements();
     151      249782 :   int nof_buckets = table->NumberOfBuckets();
     152             :   // Convert the dictionary to a linear list.
     153      249782 :   Handle<FixedArray> result = Handle<FixedArray>::cast(table);
     154             :   // From this point on table is no longer a valid OrderedHashSet.
     155      249782 :   result->set_map(ReadOnlyRoots(isolate).fixed_array_map());
     156             :   int const kMaxStringTableEntries =
     157      249782 :       isolate->heap()->MaxNumberToStringCacheSize();
     158    10241486 :   for (int i = 0; i < length; i++) {
     159     9991704 :     int index = HashTableStartIndex() + nof_buckets + (i * kEntrySize);
     160     9991704 :     Object key = table->get(index);
     161     9991704 :     if (convert == GetKeysConversion::kConvertToString) {
     162             :       uint32_t index_value;
     163     9899553 :       if (key->ToArrayIndex(&index_value)) {
     164             :         // Avoid trashing the Number2String cache if indices get very large.
     165     3517607 :         bool use_cache = i < kMaxStringTableEntries;
     166     7035214 :         key = *isolate->factory()->Uint32ToString(index_value, use_cache);
     167             :       } else {
     168     6381946 :         CHECK(key->IsName());
     169             :       }
     170             :     }
     171     9991704 :     result->set(i, key);
     172             :   }
     173      249782 :   return FixedArray::ShrinkOrEmpty(isolate, result, length);
     174             : }
     175             : 
     176          15 : HeapObject OrderedHashSet::GetEmpty(ReadOnlyRoots ro_roots) {
     177          15 :   return ro_roots.empty_ordered_hash_set();
     178             : }
     179             : 
     180          45 : HeapObject OrderedHashMap::GetEmpty(ReadOnlyRoots ro_roots) {
     181          45 :   return ro_roots.empty_ordered_hash_map();
     182             : }
     183             : 
     184             : template <class Derived, int entrysize>
     185      511278 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
     186             :     Isolate* isolate, Handle<Derived> table, int new_capacity) {
     187             :   DCHECK(!table->IsObsolete());
     188             : 
     189             :   Handle<Derived> new_table = Derived::Allocate(
     190      511278 :       isolate, new_capacity, Heap::InNewSpace(*table) ? NOT_TENURED : TENURED);
     191      511278 :   int nof = table->NumberOfElements();
     192      511278 :   int nod = table->NumberOfDeletedElements();
     193      511278 :   int new_buckets = new_table->NumberOfBuckets();
     194             :   int new_entry = 0;
     195             :   int removed_holes_index = 0;
     196             : 
     197             :   DisallowHeapAllocation no_gc;
     198    23560997 :   for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
     199    23049719 :     Object key = table->KeyAt(old_entry);
     200    23049719 :     if (key->IsTheHole(isolate)) {
     201      488562 :       table->SetRemovedIndexAt(removed_holes_index++, old_entry);
     202      244281 :       continue;
     203             :     }
     204             : 
     205    22805438 :     Object hash = key->GetHash();
     206    22805438 :     int bucket = Smi::ToInt(hash) & (new_buckets - 1);
     207    45610876 :     Object chain_entry = new_table->get(HashTableStartIndex() + bucket);
     208             :     new_table->set(HashTableStartIndex() + bucket, Smi::FromInt(new_entry));
     209    45610876 :     int new_index = new_table->EntryToIndex(new_entry);
     210    45610876 :     int old_index = table->EntryToIndex(old_entry);
     211    48035019 :     for (int i = 0; i < entrysize; ++i) {
     212    50459162 :       Object value = table->get(old_index + i);
     213    50459162 :       new_table->set(new_index + i, value);
     214             :     }
     215    45610876 :     new_table->set(new_index + kChainOffset, chain_entry);
     216    22805436 :     ++new_entry;
     217             :   }
     218             : 
     219             :   DCHECK_EQ(nod, removed_holes_index);
     220             : 
     221             :   new_table->SetNumberOfElements(nof);
     222     1022556 :   table->SetNextTable(*new_table);
     223             : 
     224      511278 :   return new_table;
     225             : }
     226             : 
     227           0 : Handle<OrderedHashSet> OrderedHashSet::Rehash(Isolate* isolate,
     228             :                                               Handle<OrderedHashSet> table,
     229             :                                               int new_capacity) {
     230             :   return OrderedHashTable<OrderedHashSet, 1>::Rehash(isolate, table,
     231      345854 :                                                      new_capacity);
     232             : }
     233             : 
     234           0 : Handle<OrderedHashMap> OrderedHashMap::Rehash(Isolate* isolate,
     235             :                                               Handle<OrderedHashMap> table,
     236             :                                               int new_capacity) {
     237             :   return OrderedHashTable<OrderedHashMap, 2>::Rehash(isolate, table,
     238      165309 :                                                      new_capacity);
     239             : }
     240             : 
     241         115 : Handle<OrderedNameDictionary> OrderedNameDictionary::Rehash(
     242             :     Isolate* isolate, Handle<OrderedNameDictionary> table, int new_capacity) {
     243             :   Handle<OrderedNameDictionary> new_table =
     244             :       OrderedHashTable<OrderedNameDictionary, 3>::Rehash(isolate, table,
     245         115 :                                                          new_capacity);
     246         230 :   new_table->SetHash(table->Hash());
     247         115 :   return new_table;
     248             : }
     249             : 
     250             : template <class Derived, int entrysize>
     251          80 : bool OrderedHashTable<Derived, entrysize>::Delete(Isolate* isolate,
     252             :                                                   Derived table, Object key) {
     253             :   DisallowHeapAllocation no_gc;
     254          80 :   int entry = table->FindEntry(isolate, key);
     255          80 :   if (entry == kNotFound) return false;
     256             : 
     257          40 :   int nof = table->NumberOfElements();
     258          40 :   int nod = table->NumberOfDeletedElements();
     259             :   int index = table->EntryToIndex(entry);
     260             : 
     261          40 :   Object hole = ReadOnlyRoots(isolate).the_hole_value();
     262         100 :   for (int i = 0; i < entrysize; ++i) {
     263          60 :     table->set(index + i, hole);
     264             :   }
     265             : 
     266          40 :   table->SetNumberOfElements(nof - 1);
     267          40 :   table->SetNumberOfDeletedElements(nod + 1);
     268             : 
     269          40 :   return true;
     270             : }
     271             : 
     272      141139 : Address OrderedHashMap::GetHash(Isolate* isolate, Address raw_key) {
     273             :   DisallowHeapAllocation no_gc;
     274             :   Object key(raw_key);
     275      141139 :   Object hash = key->GetHash();
     276             :   // If the object does not have an identity hash, it was never used as a key
     277      141139 :   if (hash->IsUndefined(isolate)) return Smi::FromInt(-1).ptr();
     278             :   DCHECK(hash->IsSmi());
     279             :   DCHECK_GE(Smi::cast(hash)->value(), 0);
     280      141139 :   return hash.ptr();
     281             : }
     282             : 
     283        5200 : Handle<OrderedHashMap> OrderedHashMap::Add(Isolate* isolate,
     284             :                                            Handle<OrderedHashMap> table,
     285             :                                            Handle<Object> key,
     286             :                                            Handle<Object> value) {
     287       10400 :   int hash = key->GetOrCreateHash(isolate)->value();
     288        5200 :   int entry = table->HashToEntry(hash);
     289             :   // Walk the chain of the bucket and try finding the key.
     290             :   {
     291             :     DisallowHeapAllocation no_gc;
     292        5200 :     Object raw_key = *key;
     293       16775 :     while (entry != kNotFound) {
     294        6395 :       Object candidate_key = table->KeyAt(entry);
     295             :       // Do not add if we have the key already
     296        6395 :       if (candidate_key->SameValueZero(raw_key)) return table;
     297        6375 :       entry = table->NextChainEntry(entry);
     298             :     }
     299             :   }
     300             : 
     301        5180 :   table = OrderedHashMap::EnsureGrowable(isolate, table);
     302             :   // Read the existing bucket values.
     303       10360 :   int bucket = table->HashToBucket(hash);
     304        5180 :   int previous_entry = table->HashToEntry(hash);
     305        5180 :   int nof = table->NumberOfElements();
     306             :   // Insert a new entry at the end,
     307        5180 :   int new_entry = nof + table->NumberOfDeletedElements();
     308       10360 :   int new_index = table->EntryToIndex(new_entry);
     309        5180 :   table->set(new_index, *key);
     310       10360 :   table->set(new_index + kValueOffset, *value);
     311             :   table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
     312             :   // and point the bucket to the new entry.
     313             :   table->set(HashTableStartIndex() + bucket, Smi::FromInt(new_entry));
     314        5180 :   table->SetNumberOfElements(nof + 1);
     315        5180 :   return table;
     316             : }
     317             : 
     318             : template <>
     319     3948680 : int OrderedHashTable<OrderedNameDictionary, 3>::FindEntry(Isolate* isolate,
     320             :                                                           Object key) {
     321             :   DisallowHeapAllocation no_gc;
     322             : 
     323             :   DCHECK(key->IsUniqueName());
     324     3948680 :   Name raw_key = Name::cast(key);
     325             : 
     326     3948680 :   int entry = HashToEntry(raw_key->Hash());
     327    11948775 :   while (entry != kNotFound) {
     328     6515375 :     Object candidate_key = KeyAt(entry);
     329             :     DCHECK(candidate_key->IsTheHole() ||
     330             :            Name::cast(candidate_key)->IsUniqueName());
     331     6515375 :     if (candidate_key == raw_key) return entry;
     332             : 
     333             :     // TODO(gsathya): This is loading the bucket count from the hash
     334             :     // table for every iteration. This should be peeled out of the
     335             :     // loop.
     336     4051415 :     entry = NextChainEntry(entry);
     337             :   }
     338             : 
     339             :   return kNotFound;
     340             : }
     341             : 
     342       10800 : Handle<OrderedNameDictionary> OrderedNameDictionary::Add(
     343             :     Isolate* isolate, Handle<OrderedNameDictionary> table, Handle<Name> key,
     344             :     Handle<Object> value, PropertyDetails details) {
     345             :   DCHECK_EQ(kNotFound, table->FindEntry(isolate, *key));
     346             : 
     347       10800 :   table = OrderedNameDictionary::EnsureGrowable(isolate, table);
     348             :   // Read the existing bucket values.
     349       10800 :   int hash = key->Hash();
     350       21600 :   int bucket = table->HashToBucket(hash);
     351       10800 :   int previous_entry = table->HashToEntry(hash);
     352       10800 :   int nof = table->NumberOfElements();
     353             :   // Insert a new entry at the end,
     354       10800 :   int new_entry = nof + table->NumberOfDeletedElements();
     355       21600 :   int new_index = table->EntryToIndex(new_entry);
     356       21600 :   table->set(new_index, *key);
     357       21600 :   table->set(new_index + kValueOffset, *value);
     358             : 
     359             :   // TODO(gsathya): Optimize how PropertyDetails are stored in this
     360             :   // dictionary to save memory (by reusing padding?) and performance
     361             :   // (by not doing the Smi conversion).
     362             :   table->set(new_index + kPropertyDetailsOffset, details.AsSmi());
     363             : 
     364             :   table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
     365             :   // and point the bucket to the new entry.
     366             :   table->set(HashTableStartIndex() + bucket, Smi::FromInt(new_entry));
     367       10800 :   table->SetNumberOfElements(nof + 1);
     368       10800 :   return table;
     369             : }
     370             : 
     371         510 : void OrderedNameDictionary::SetEntry(Isolate* isolate, int entry, Object key,
     372             :                                      Object value, PropertyDetails details) {
     373             :   DisallowHeapAllocation gc;
     374             :   DCHECK_IMPLIES(!key->IsName(), key->IsTheHole(isolate));
     375             :   DisallowHeapAllocation no_gc;
     376         510 :   int index = EntryToIndex(entry);
     377         510 :   this->set(index, key);
     378         510 :   this->set(index + kValueOffset, value);
     379             : 
     380             :   // TODO(gsathya): Optimize how PropertyDetails are stored in this
     381             :   // dictionary to save memory (by reusing padding?) and performance
     382             :   // (by not doing the Smi conversion).
     383             :   this->set(index + kPropertyDetailsOffset, details.AsSmi());
     384         510 : }
     385             : 
     386         505 : Handle<OrderedNameDictionary> OrderedNameDictionary::DeleteEntry(
     387             :     Isolate* isolate, Handle<OrderedNameDictionary> table, int entry) {
     388             :   DCHECK_NE(entry, kNotFound);
     389             : 
     390         505 :   Object hole = ReadOnlyRoots(isolate).the_hole_value();
     391         505 :   PropertyDetails details = PropertyDetails::Empty();
     392         505 :   table->SetEntry(isolate, entry, hole, hole, details);
     393             : 
     394         505 :   int nof = table->NumberOfElements();
     395         505 :   table->SetNumberOfElements(nof - 1);
     396         505 :   int nod = table->NumberOfDeletedElements();
     397         505 :   table->SetNumberOfDeletedElements(nod + 1);
     398             : 
     399         505 :   return Shrink(isolate, table);
     400             : }
     401             : 
     402      329561 : Handle<OrderedHashSet> OrderedHashSet::Allocate(Isolate* isolate, int capacity,
     403             :                                                 PretenureFlag pretenure) {
     404             :   return OrderedHashTable<OrderedHashSet, 1>::Allocate(isolate, capacity,
     405      675420 :                                                        pretenure);
     406             : }
     407             : 
     408          33 : Handle<OrderedHashMap> OrderedHashMap::Allocate(Isolate* isolate, int capacity,
     409             :                                                 PretenureFlag pretenure) {
     410             :   return OrderedHashTable<OrderedHashMap, 2>::Allocate(isolate, capacity,
     411      165347 :                                                        pretenure);
     412             : }
     413             : 
     414         155 : Handle<OrderedNameDictionary> OrderedNameDictionary::Allocate(
     415             :     Isolate* isolate, int capacity, PretenureFlag pretenure) {
     416             :   Handle<OrderedNameDictionary> table =
     417             :       OrderedHashTable<OrderedNameDictionary, 3>::Allocate(isolate, capacity,
     418         155 :                                                            pretenure);
     419             :   table->SetHash(PropertyArray::kNoHashSentinel);
     420         155 :   return table;
     421             : }
     422             : 
     423             : template Handle<OrderedHashSet>
     424             : OrderedHashTable<OrderedHashSet, 1>::EnsureGrowable(
     425             :     Isolate* isolate, Handle<OrderedHashSet> table);
     426             : 
     427             : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Shrink(
     428             :     Isolate* isolate, Handle<OrderedHashSet> table);
     429             : 
     430             : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Clear(
     431             :     Isolate* isolate, Handle<OrderedHashSet> table);
     432             : 
     433             : template bool OrderedHashTable<OrderedHashSet, 1>::HasKey(Isolate* isolate,
     434             :                                                           OrderedHashSet table,
     435             :                                                           Object key);
     436             : 
     437             : template bool OrderedHashTable<OrderedHashSet, 1>::Delete(Isolate* isolate,
     438             :                                                           OrderedHashSet table,
     439             :                                                           Object key);
     440             : 
     441             : template int OrderedHashTable<OrderedHashSet, 1>::FindEntry(Isolate* isolate,
     442             :                                                             Object key);
     443             : 
     444             : template Handle<OrderedHashMap>
     445             : OrderedHashTable<OrderedHashMap, 2>::EnsureGrowable(
     446             :     Isolate* isolate, Handle<OrderedHashMap> table);
     447             : 
     448             : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Shrink(
     449             :     Isolate* isolate, Handle<OrderedHashMap> table);
     450             : 
     451             : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Clear(
     452             :     Isolate* isolate, Handle<OrderedHashMap> table);
     453             : 
     454             : template bool OrderedHashTable<OrderedHashMap, 2>::HasKey(Isolate* isolate,
     455             :                                                           OrderedHashMap table,
     456             :                                                           Object key);
     457             : 
     458             : template bool OrderedHashTable<OrderedHashMap, 2>::Delete(Isolate* isolate,
     459             :                                                           OrderedHashMap table,
     460             :                                                           Object key);
     461             : 
     462             : template int OrderedHashTable<OrderedHashMap, 2>::FindEntry(Isolate* isolate,
     463             :                                                             Object key);
     464             : 
     465             : template Handle<OrderedNameDictionary>
     466             : OrderedHashTable<OrderedNameDictionary, 3>::Shrink(
     467             :     Isolate* isolate, Handle<OrderedNameDictionary> table);
     468             : 
     469             : template Handle<OrderedNameDictionary>
     470             : OrderedHashTable<OrderedNameDictionary, 3>::EnsureGrowable(
     471             :     Isolate* isolate, Handle<OrderedNameDictionary> table);
     472             : 
     473             : template <>
     474             : Handle<SmallOrderedHashSet>
     475           0 : SmallOrderedHashTable<SmallOrderedHashSet>::Allocate(Isolate* isolate,
     476             :                                                      int capacity,
     477             :                                                      PretenureFlag pretenure) {
     478          70 :   return isolate->factory()->NewSmallOrderedHashSet(capacity, pretenure);
     479             : }
     480             : 
     481             : template <>
     482             : Handle<SmallOrderedHashMap>
     483           0 : SmallOrderedHashTable<SmallOrderedHashMap>::Allocate(Isolate* isolate,
     484             :                                                      int capacity,
     485             :                                                      PretenureFlag pretenure) {
     486          70 :   return isolate->factory()->NewSmallOrderedHashMap(capacity, pretenure);
     487             : }
     488             : 
     489             : template <>
     490             : Handle<SmallOrderedNameDictionary>
     491           0 : SmallOrderedHashTable<SmallOrderedNameDictionary>::Allocate(
     492             :     Isolate* isolate, int capacity, PretenureFlag pretenure) {
     493         165 :   return isolate->factory()->NewSmallOrderedNameDictionary(capacity, pretenure);
     494             : }
     495             : 
     496             : template <class Derived>
     497         455 : void SmallOrderedHashTable<Derived>::Initialize(Isolate* isolate,
     498             :                                                 int capacity) {
     499             :   DisallowHeapAllocation no_gc;
     500         455 :   int num_buckets = capacity / kLoadFactor;
     501             :   int num_chains = capacity;
     502             : 
     503             :   SetNumberOfBuckets(num_buckets);
     504             :   SetNumberOfElements(0);
     505             :   SetNumberOfDeletedElements(0);
     506             : 
     507             :   Address hashtable_start = GetHashTableStartAddress(capacity);
     508             :   memset(reinterpret_cast<byte*>(hashtable_start), kNotFound,
     509         455 :          num_buckets + num_chains);
     510             : 
     511         455 :   if (Heap::InNewSpace(*this)) {
     512             :     MemsetTagged(RawField(DataTableStartOffset()),
     513             :                  ReadOnlyRoots(isolate).the_hole_value(),
     514         455 :                  capacity * Derived::kEntrySize);
     515             :   } else {
     516           0 :     for (int i = 0; i < capacity; i++) {
     517           0 :       for (int j = 0; j < Derived::kEntrySize; j++) {
     518           0 :         SetDataEntry(i, j, ReadOnlyRoots(isolate).the_hole_value());
     519             :       }
     520             :     }
     521             :   }
     522             : 
     523             : #ifdef DEBUG
     524             :   for (int i = 0; i < num_buckets; ++i) {
     525             :     DCHECK_EQ(kNotFound, GetFirstEntry(i));
     526             :   }
     527             : 
     528             :   for (int i = 0; i < num_chains; ++i) {
     529             :     DCHECK_EQ(kNotFound, GetNextEntry(i));
     530             :   }
     531             : 
     532             :   for (int i = 0; i < capacity; ++i) {
     533             :     for (int j = 0; j < Derived::kEntrySize; j++) {
     534             :       DCHECK_EQ(ReadOnlyRoots(isolate).the_hole_value(), GetDataEntry(i, j));
     535             :     }
     536             :   }
     537             : #endif  // DEBUG
     538         455 : }
     539             : 
     540        2635 : MaybeHandle<SmallOrderedHashSet> SmallOrderedHashSet::Add(
     541             :     Isolate* isolate, Handle<SmallOrderedHashSet> table, Handle<Object> key) {
     542        2635 :   if (table->HasKey(isolate, key)) return table;
     543             : 
     544        2605 :   if (table->UsedCapacity() >= table->Capacity()) {
     545             :     MaybeHandle<SmallOrderedHashSet> new_table =
     546          70 :         SmallOrderedHashSet::Grow(isolate, table);
     547          70 :     if (!new_table.ToHandle(&table)) {
     548           5 :       return MaybeHandle<SmallOrderedHashSet>();
     549             :     }
     550             :   }
     551             : 
     552        5200 :   int hash = key->GetOrCreateHash(isolate)->value();
     553             :   int nof = table->NumberOfElements();
     554             : 
     555             :   // Read the existing bucket values.
     556             :   int bucket = table->HashToBucket(hash);
     557             :   int previous_entry = table->HashToFirstEntry(hash);
     558             : 
     559             :   // Insert a new entry at the end,
     560        2600 :   int new_entry = nof + table->NumberOfDeletedElements();
     561             : 
     562        2600 :   table->SetDataEntry(new_entry, SmallOrderedHashSet::kKeyIndex, *key);
     563        2600 :   table->SetFirstEntry(bucket, new_entry);
     564             :   table->SetNextEntry(new_entry, previous_entry);
     565             : 
     566             :   // and update book keeping.
     567        2600 :   table->SetNumberOfElements(nof + 1);
     568             : 
     569        2600 :   return table;
     570             : }
     571             : 
     572        2635 : MaybeHandle<SmallOrderedHashMap> SmallOrderedHashMap::Add(
     573             :     Isolate* isolate, Handle<SmallOrderedHashMap> table, Handle<Object> key,
     574             :     Handle<Object> value) {
     575        2635 :   if (table->HasKey(isolate, key)) return table;
     576             : 
     577        2605 :   if (table->UsedCapacity() >= table->Capacity()) {
     578             :     MaybeHandle<SmallOrderedHashMap> new_table =
     579          70 :         SmallOrderedHashMap::Grow(isolate, table);
     580          70 :     if (!new_table.ToHandle(&table)) {
     581           5 :       return MaybeHandle<SmallOrderedHashMap>();
     582             :     }
     583             :   }
     584             : 
     585        5200 :   int hash = key->GetOrCreateHash(isolate)->value();
     586             :   int nof = table->NumberOfElements();
     587             : 
     588             :   // Read the existing bucket values.
     589             :   int bucket = table->HashToBucket(hash);
     590             :   int previous_entry = table->HashToFirstEntry(hash);
     591             : 
     592             :   // Insert a new entry at the end,
     593        2600 :   int new_entry = nof + table->NumberOfDeletedElements();
     594             : 
     595        2600 :   table->SetDataEntry(new_entry, SmallOrderedHashMap::kValueIndex, *value);
     596        2600 :   table->SetDataEntry(new_entry, SmallOrderedHashMap::kKeyIndex, *key);
     597        2600 :   table->SetFirstEntry(bucket, new_entry);
     598             :   table->SetNextEntry(new_entry, previous_entry);
     599             : 
     600             :   // and update book keeping.
     601        2600 :   table->SetNumberOfElements(nof + 1);
     602             : 
     603        2600 :   return table;
     604             : }
     605             : 
     606             : template <>
     607     1298080 : int SmallOrderedHashTable<SmallOrderedNameDictionary>::FindEntry(
     608             :     Isolate* isolate, Object key) {
     609             :   DisallowHeapAllocation no_gc;
     610             :   DCHECK(key->IsUniqueName());
     611     1298080 :   Name raw_key = Name::cast(key);
     612             : 
     613     1298080 :   int entry = HashToFirstEntry(raw_key->Hash());
     614             : 
     615             :   // Walk the chain in the bucket to find the key.
     616     5326180 :   while (entry != kNotFound) {
     617             :     Object candidate_key = KeyAt(entry);
     618     2892070 :     if (candidate_key == key) return entry;
     619             :     entry = GetNextEntry(entry);
     620             :   }
     621             : 
     622             :   return kNotFound;
     623             : }
     624             : 
     625        5140 : MaybeHandle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::Add(
     626             :     Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
     627             :     Handle<Name> key, Handle<Object> value, PropertyDetails details) {
     628             :   DCHECK_EQ(kNotFound, table->FindEntry(isolate, *key));
     629             : 
     630        5140 :   if (table->UsedCapacity() >= table->Capacity()) {
     631             :     MaybeHandle<SmallOrderedNameDictionary> new_table =
     632         130 :         SmallOrderedNameDictionary::Grow(isolate, table);
     633         130 :     if (!new_table.ToHandle(&table)) {
     634          10 :       return MaybeHandle<SmallOrderedNameDictionary>();
     635             :     }
     636             :   }
     637             : 
     638             :   int nof = table->NumberOfElements();
     639             : 
     640             :   // Read the existing bucket values.
     641        5130 :   int hash = key->Hash();
     642             :   int bucket = table->HashToBucket(hash);
     643             :   int previous_entry = table->HashToFirstEntry(hash);
     644             : 
     645             :   // Insert a new entry at the end,
     646        5130 :   int new_entry = nof + table->NumberOfDeletedElements();
     647             : 
     648       10260 :   table->SetDataEntry(new_entry, SmallOrderedNameDictionary::kValueIndex,
     649        5130 :                       *value);
     650       10260 :   table->SetDataEntry(new_entry, SmallOrderedNameDictionary::kKeyIndex, *key);
     651             : 
     652             :   // TODO(gsathya): PropertyDetails should be stored as part of the
     653             :   // data table to save more memory.
     654       10260 :   table->SetDataEntry(new_entry,
     655             :                       SmallOrderedNameDictionary::kPropertyDetailsIndex,
     656       15390 :                       details.AsSmi());
     657        5130 :   table->SetFirstEntry(bucket, new_entry);
     658             :   table->SetNextEntry(new_entry, previous_entry);
     659             : 
     660             :   // and update book keeping.
     661        5130 :   table->SetNumberOfElements(nof + 1);
     662             : 
     663        5130 :   return table;
     664             : }
     665             : 
     666        1280 : void SmallOrderedNameDictionary::SetEntry(Isolate* isolate, int entry,
     667             :                                           Object key, Object value,
     668             :                                           PropertyDetails details) {
     669             :   DCHECK_IMPLIES(!key->IsName(), key->IsTheHole(isolate));
     670        1280 :   SetDataEntry(entry, SmallOrderedNameDictionary::kValueIndex, value);
     671        1280 :   SetDataEntry(entry, SmallOrderedNameDictionary::kKeyIndex, key);
     672             : 
     673             :   // TODO(gsathya): PropertyDetails should be stored as part of the
     674             :   // data table to save more memory.
     675             :   SetDataEntry(entry, SmallOrderedNameDictionary::kPropertyDetailsIndex,
     676        1280 :                details.AsSmi());
     677        1280 : }
     678             : 
     679             : template <class Derived>
     680      334790 : bool SmallOrderedHashTable<Derived>::HasKey(Isolate* isolate,
     681             :                                             Handle<Object> key) {
     682             :   DisallowHeapAllocation no_gc;
     683      334790 :   return FindEntry(isolate, *key) != kNotFound;
     684             : }
     685             : 
     686             : template <class Derived>
     687          80 : bool SmallOrderedHashTable<Derived>::Delete(Isolate* isolate, Derived table,
     688             :                                             Object key) {
     689             :   DisallowHeapAllocation no_gc;
     690          80 :   int entry = table->FindEntry(isolate, key);
     691          80 :   if (entry == kNotFound) return false;
     692             : 
     693             :   int nof = table->NumberOfElements();
     694             :   int nod = table->NumberOfDeletedElements();
     695             : 
     696          40 :   Object hole = ReadOnlyRoots(isolate).the_hole_value();
     697         100 :   for (int j = 0; j < Derived::kEntrySize; j++) {
     698          60 :     table->SetDataEntry(entry, j, hole);
     699             :   }
     700             : 
     701          40 :   table->SetNumberOfElements(nof - 1);
     702          40 :   table->SetNumberOfDeletedElements(nod + 1);
     703             : 
     704          40 :   return true;
     705             : }
     706             : 
     707        1275 : Handle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::DeleteEntry(
     708             :     Isolate* isolate, Handle<SmallOrderedNameDictionary> table, int entry) {
     709             :   DCHECK_NE(entry, kNotFound);
     710             :   {
     711             :     DisallowHeapAllocation no_gc;
     712        1275 :     Object hole = ReadOnlyRoots(isolate).the_hole_value();
     713        1275 :     PropertyDetails details = PropertyDetails::Empty();
     714        1275 :     table->SetEntry(isolate, entry, hole, hole, details);
     715             : 
     716             :     int nof = table->NumberOfElements();
     717        1275 :     table->SetNumberOfElements(nof - 1);
     718             :     int nod = table->NumberOfDeletedElements();
     719        1275 :     table->SetNumberOfDeletedElements(nod + 1);
     720             :   }
     721        1275 :   return Shrink(isolate, table);
     722             : }
     723             : 
     724             : template <class Derived>
     725         290 : Handle<Derived> SmallOrderedHashTable<Derived>::Rehash(Isolate* isolate,
     726             :                                                        Handle<Derived> table,
     727             :                                                        int new_capacity) {
     728             :   DCHECK_GE(kMaxCapacity, new_capacity);
     729             : 
     730             :   Handle<Derived> new_table = SmallOrderedHashTable<Derived>::Allocate(
     731         290 :       isolate, new_capacity, Heap::InNewSpace(*table) ? NOT_TENURED : TENURED);
     732             :   int nof = table->NumberOfElements();
     733             :   int nod = table->NumberOfDeletedElements();
     734             :   int new_entry = 0;
     735             : 
     736             :   {
     737             :     DisallowHeapAllocation no_gc;
     738       12280 :     for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
     739       11990 :       Object key = table->KeyAt(old_entry);
     740       13305 :       if (key->IsTheHole(isolate)) continue;
     741             : 
     742       10675 :       int hash = Smi::ToInt(key->GetHash());
     743             :       int bucket = new_table->HashToBucket(hash);
     744             :       int chain = new_table->GetFirstEntry(bucket);
     745             : 
     746       10675 :       new_table->SetFirstEntry(bucket, new_entry);
     747             :       new_table->SetNextEntry(new_entry, chain);
     748             : 
     749       35140 :       for (int i = 0; i < Derived::kEntrySize; ++i) {
     750       24465 :         Object value = table->GetDataEntry(old_entry, i);
     751       24465 :         new_table->SetDataEntry(new_entry, i, value);
     752             :       }
     753             : 
     754       10675 :       ++new_entry;
     755             :     }
     756             : 
     757             :     new_table->SetNumberOfElements(nof);
     758             :   }
     759         290 :   return new_table;
     760             : }
     761             : 
     762           0 : Handle<SmallOrderedHashSet> SmallOrderedHashSet::Rehash(
     763             :     Isolate* isolate, Handle<SmallOrderedHashSet> table, int new_capacity) {
     764             :   return SmallOrderedHashTable<SmallOrderedHashSet>::Rehash(isolate, table,
     765          65 :                                                             new_capacity);
     766             : }
     767             : 
     768           0 : Handle<SmallOrderedHashMap> SmallOrderedHashMap::Rehash(
     769             :     Isolate* isolate, Handle<SmallOrderedHashMap> table, int new_capacity) {
     770             :   return SmallOrderedHashTable<SmallOrderedHashMap>::Rehash(isolate, table,
     771          65 :                                                             new_capacity);
     772             : }
     773             : 
     774         160 : Handle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::Rehash(
     775             :     Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
     776             :     int new_capacity) {
     777             :   Handle<SmallOrderedNameDictionary> new_table =
     778             :       SmallOrderedHashTable<SmallOrderedNameDictionary>::Rehash(isolate, table,
     779         160 :                                                                 new_capacity);
     780             :   new_table->SetHash(table->Hash());
     781         160 :   return new_table;
     782             : }
     783             : 
     784             : template <class Derived>
     785        1275 : Handle<Derived> SmallOrderedHashTable<Derived>::Shrink(Isolate* isolate,
     786             :                                                        Handle<Derived> table) {
     787             :   int nof = table->NumberOfElements();
     788             :   int capacity = table->Capacity();
     789        1275 :   if (nof >= (capacity >> 2)) return table;
     790          40 :   return Derived::Rehash(isolate, table, capacity / 2);
     791             : }
     792             : 
     793             : template <class Derived>
     794         270 : MaybeHandle<Derived> SmallOrderedHashTable<Derived>::Grow(
     795             :     Isolate* isolate, Handle<Derived> table) {
     796             :   int capacity = table->Capacity();
     797             :   int new_capacity = capacity;
     798             : 
     799             :   // Don't need to grow if we can simply clear out deleted entries instead.
     800             :   // TODO(gsathya): Compact in place, instead of allocating a new table.
     801         270 :   if (table->NumberOfDeletedElements() < (capacity >> 1)) {
     802         260 :     new_capacity = capacity << 1;
     803             : 
     804             :     // The max capacity of our table is 254. We special case for 256 to
     805             :     // account for our growth strategy, otherwise we would only fill up
     806             :     // to 128 entries in our table.
     807         260 :     if (new_capacity == kGrowthHack) {
     808             :       new_capacity = kMaxCapacity;
     809             :     }
     810             : 
     811             :     // We need to migrate to a bigger hash table.
     812         260 :     if (new_capacity > kMaxCapacity) {
     813          20 :       return MaybeHandle<Derived>();
     814             :     }
     815             :   }
     816             : 
     817         250 :   return Derived::Rehash(isolate, table, new_capacity);
     818             : }
     819             : 
     820             : template <class Derived>
     821      334870 : int SmallOrderedHashTable<Derived>::FindEntry(Isolate* isolate, Object key) {
     822             :   DisallowHeapAllocation no_gc;
     823      334870 :   Object hash = key->GetHash();
     824             : 
     825      334870 :   if (hash->IsUndefined(isolate)) return kNotFound;
     826      334850 :   int entry = HashToFirstEntry(Smi::ToInt(hash));
     827             : 
     828             :   // Walk the chain in the bucket to find the key.
     829     1091170 :   while (entry != kNotFound) {
     830      750860 :     Object candidate_key = KeyAt(entry);
     831      750860 :     if (candidate_key->SameValueZero(key)) return entry;
     832             :     entry = GetNextEntry(entry);
     833             :   }
     834             :   return kNotFound;
     835             : }
     836             : 
     837             : template bool SmallOrderedHashTable<SmallOrderedHashSet>::HasKey(
     838             :     Isolate* isolate, Handle<Object> key);
     839             : template Handle<SmallOrderedHashSet>
     840             : SmallOrderedHashTable<SmallOrderedHashSet>::Rehash(
     841             :     Isolate* isolate, Handle<SmallOrderedHashSet> table, int new_capacity);
     842             : template Handle<SmallOrderedHashSet>
     843             : SmallOrderedHashTable<SmallOrderedHashSet>::Shrink(
     844             :     Isolate* isolate, Handle<SmallOrderedHashSet> table);
     845             : template MaybeHandle<SmallOrderedHashSet>
     846             : SmallOrderedHashTable<SmallOrderedHashSet>::Grow(
     847             :     Isolate* isolate, Handle<SmallOrderedHashSet> table);
     848             : template void SmallOrderedHashTable<SmallOrderedHashSet>::Initialize(
     849             :     Isolate* isolate, int capacity);
     850             : 
     851             : template bool SmallOrderedHashTable<SmallOrderedHashMap>::HasKey(
     852             :     Isolate* isolate, Handle<Object> key);
     853             : template Handle<SmallOrderedHashMap>
     854             : SmallOrderedHashTable<SmallOrderedHashMap>::Rehash(
     855             :     Isolate* isolate, Handle<SmallOrderedHashMap> table, int new_capacity);
     856             : template Handle<SmallOrderedHashMap>
     857             : SmallOrderedHashTable<SmallOrderedHashMap>::Shrink(
     858             :     Isolate* isolate, Handle<SmallOrderedHashMap> table);
     859             : template MaybeHandle<SmallOrderedHashMap>
     860             : SmallOrderedHashTable<SmallOrderedHashMap>::Grow(
     861             :     Isolate* isolate, Handle<SmallOrderedHashMap> table);
     862             : template void SmallOrderedHashTable<SmallOrderedHashMap>::Initialize(
     863             :     Isolate* isolate, int capacity);
     864             : 
     865             : template bool SmallOrderedHashTable<SmallOrderedHashMap>::Delete(
     866             :     Isolate* isolate, SmallOrderedHashMap table, Object key);
     867             : template bool SmallOrderedHashTable<SmallOrderedHashSet>::Delete(
     868             :     Isolate* isolate, SmallOrderedHashSet table, Object key);
     869             : 
     870             : template void SmallOrderedHashTable<SmallOrderedNameDictionary>::Initialize(
     871             :     Isolate* isolate, int capacity);
     872             : template Handle<SmallOrderedNameDictionary>
     873             : SmallOrderedHashTable<SmallOrderedNameDictionary>::Shrink(
     874             :     Isolate* isolate, Handle<SmallOrderedNameDictionary> table);
     875             : 
     876             : template <class SmallTable, class LargeTable>
     877          15 : Handle<HeapObject> OrderedHashTableHandler<SmallTable, LargeTable>::Allocate(
     878             :     Isolate* isolate, int capacity) {
     879          15 :   if (capacity < SmallTable::kMaxCapacity) {
     880          15 :     return SmallTable::Allocate(isolate, capacity);
     881             :   }
     882             : 
     883           0 :   return LargeTable::Allocate(isolate, capacity);
     884             : }
     885             : 
     886             : template Handle<HeapObject>
     887             : OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet>::Allocate(
     888             :     Isolate* isolate, int capacity);
     889             : template Handle<HeapObject>
     890             : OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap>::Allocate(
     891             :     Isolate* isolate, int capacity);
     892             : template Handle<HeapObject>
     893             : OrderedHashTableHandler<SmallOrderedNameDictionary,
     894             :                         OrderedNameDictionary>::Allocate(Isolate* isolate,
     895             :                                                          int capacity);
     896             : 
     897             : template <class SmallTable, class LargeTable>
     898             : bool OrderedHashTableHandler<SmallTable, LargeTable>::Delete(
     899             :     Handle<HeapObject> table, Handle<Object> key) {
     900             :   if (SmallTable::Is(table)) {
     901             :     return SmallTable::Delete(Handle<SmallTable>::cast(table), key);
     902             :   }
     903             : 
     904             :   DCHECK(LargeTable::Is(table));
     905             :   // Note: Once we migrate to the a big hash table, we never migrate
     906             :   // down to a smaller hash table.
     907             :   return LargeTable::Delete(Handle<LargeTable>::cast(table), key);
     908             : }
     909             : 
     910             : template <class SmallTable, class LargeTable>
     911     5248030 : bool OrderedHashTableHandler<SmallTable, LargeTable>::HasKey(
     912             :     Isolate* isolate, Handle<HeapObject> table, Handle<Object> key) {
     913     5248030 :   if (SmallTable::Is(table)) {
     914      647760 :     return Handle<SmallTable>::cast(table)->HasKey(isolate, key);
     915             :   }
     916             : 
     917             :   DCHECK(LargeTable::Is(table));
     918     4924150 :   return LargeTable::HasKey(isolate, LargeTable::cast(*table), *key);
     919             : }
     920             : 
     921             : template bool
     922             : OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet>::HasKey(
     923             :     Isolate* isolate, Handle<HeapObject> table, Handle<Object> key);
     924             : template bool
     925             : OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap>::HasKey(
     926             :     Isolate* isolate, Handle<HeapObject> table, Handle<Object> key);
     927             : 
     928           5 : Handle<OrderedHashMap> OrderedHashMapHandler::AdjustRepresentation(
     929             :     Isolate* isolate, Handle<SmallOrderedHashMap> table) {
     930             :   Handle<OrderedHashMap> new_table =
     931             :       OrderedHashMap::Allocate(isolate, OrderedHashTableMinSize);
     932             :   int nof = table->NumberOfElements();
     933             :   int nod = table->NumberOfDeletedElements();
     934             : 
     935             :   // TODO(gsathya): Optimize the lookup to not re calc offsets. Also,
     936             :   // unhandlify this code as we preallocate the new backing store with
     937             :   // the proper capacity.
     938        1275 :   for (int entry = 0; entry < (nof + nod); ++entry) {
     939             :     Handle<Object> key = handle(table->KeyAt(entry), isolate);
     940        2540 :     if (key->IsTheHole(isolate)) continue;
     941             :     Handle<Object> value = handle(
     942        1270 :         table->GetDataEntry(entry, SmallOrderedHashMap::kValueIndex), isolate);
     943        1270 :     new_table = OrderedHashMap::Add(isolate, new_table, key, value);
     944             :   }
     945             : 
     946           5 :   return new_table;
     947             : }
     948             : 
     949           5 : Handle<OrderedHashSet> OrderedHashSetHandler::AdjustRepresentation(
     950             :     Isolate* isolate, Handle<SmallOrderedHashSet> table) {
     951             :   Handle<OrderedHashSet> new_table =
     952             :       OrderedHashSet::Allocate(isolate, OrderedHashTableMinSize);
     953             :   int nof = table->NumberOfElements();
     954             :   int nod = table->NumberOfDeletedElements();
     955             : 
     956             :   // TODO(gsathya): Optimize the lookup to not re calc offsets. Also,
     957             :   // unhandlify this code as we preallocate the new backing store with
     958             :   // the proper capacity.
     959        1275 :   for (int entry = 0; entry < (nof + nod); ++entry) {
     960             :     Handle<Object> key = handle(table->KeyAt(entry), isolate);
     961        2540 :     if (key->IsTheHole(isolate)) continue;
     962        1270 :     new_table = OrderedHashSet::Add(isolate, new_table, key);
     963             :   }
     964             : 
     965           5 :   return new_table;
     966             : }
     967             : 
     968             : Handle<OrderedNameDictionary>
     969           5 : OrderedNameDictionaryHandler::AdjustRepresentation(
     970             :     Isolate* isolate, Handle<SmallOrderedNameDictionary> table) {
     971             :   Handle<OrderedNameDictionary> new_table =
     972           5 :       OrderedNameDictionary::Allocate(isolate, OrderedHashTableMinSize);
     973             :   int nof = table->NumberOfElements();
     974             :   int nod = table->NumberOfDeletedElements();
     975             : 
     976             :   // TODO(gsathya): Optimize the lookup to not re calc offsets. Also,
     977             :   // unhandlify this code as we preallocate the new backing store with
     978             :   // the proper capacity.
     979        1275 :   for (int entry = 0; entry < (nof + nod); ++entry) {
     980             :     Handle<Name> key(Name::cast(table->KeyAt(entry)), isolate);
     981        2540 :     if (key->IsTheHole(isolate)) continue;
     982             :     Handle<Object> value(table->ValueAt(entry), isolate);
     983        1270 :     PropertyDetails details = table->DetailsAt(entry);
     984             :     new_table =
     985        1270 :         OrderedNameDictionary::Add(isolate, new_table, key, value, details);
     986             :   }
     987             : 
     988           5 :   return new_table;
     989             : }
     990             : 
     991        5130 : Handle<HeapObject> OrderedHashMapHandler::Add(Isolate* isolate,
     992             :                                               Handle<HeapObject> table,
     993             :                                               Handle<Object> key,
     994             :                                               Handle<Object> value) {
     995       10260 :   if (table->IsSmallOrderedHashMap()) {
     996             :     Handle<SmallOrderedHashMap> small_map =
     997        1285 :         Handle<SmallOrderedHashMap>::cast(table);
     998             :     MaybeHandle<SmallOrderedHashMap> new_map =
     999        1285 :         SmallOrderedHashMap::Add(isolate, small_map, key, value);
    1000        2565 :     if (!new_map.is_null()) return new_map.ToHandleChecked();
    1001             : 
    1002             :     // We couldn't add to the small table, let's migrate to the
    1003             :     // big table.
    1004           5 :     table = OrderedHashMapHandler::AdjustRepresentation(isolate, small_map);
    1005             :   }
    1006             : 
    1007             :   DCHECK(table->IsOrderedHashMap());
    1008             :   return OrderedHashMap::Add(isolate, Handle<OrderedHashMap>::cast(table), key,
    1009        3850 :                              value);
    1010             : }
    1011             : 
    1012        5130 : Handle<HeapObject> OrderedHashSetHandler::Add(Isolate* isolate,
    1013             :                                               Handle<HeapObject> table,
    1014             :                                               Handle<Object> key) {
    1015       10260 :   if (table->IsSmallOrderedHashSet()) {
    1016             :     Handle<SmallOrderedHashSet> small_set =
    1017        1285 :         Handle<SmallOrderedHashSet>::cast(table);
    1018             :     MaybeHandle<SmallOrderedHashSet> new_set =
    1019        1285 :         SmallOrderedHashSet::Add(isolate, small_set, key);
    1020        2565 :     if (!new_set.is_null()) return new_set.ToHandleChecked();
    1021             : 
    1022             :     // We couldn't add to the small table, let's migrate to the
    1023             :     // big table.
    1024           5 :     table = OrderedHashSetHandler::AdjustRepresentation(isolate, small_set);
    1025             :   }
    1026             : 
    1027             :   DCHECK(table->IsOrderedHashSet());
    1028        3850 :   return OrderedHashSet::Add(isolate, Handle<OrderedHashSet>::cast(table), key);
    1029             : }
    1030             : 
    1031        5125 : Handle<HeapObject> OrderedNameDictionaryHandler::Add(Isolate* isolate,
    1032             :                                                      Handle<HeapObject> table,
    1033             :                                                      Handle<Name> key,
    1034             :                                                      Handle<Object> value,
    1035             :                                                      PropertyDetails details) {
    1036       10250 :   if (table->IsSmallOrderedNameDictionary()) {
    1037             :     Handle<SmallOrderedNameDictionary> small_dict =
    1038        1275 :         Handle<SmallOrderedNameDictionary>::cast(table);
    1039             :     MaybeHandle<SmallOrderedNameDictionary> new_dict =
    1040             :         SmallOrderedNameDictionary::Add(isolate, small_dict, key, value,
    1041        1275 :                                         details);
    1042        2545 :     if (!new_dict.is_null()) return new_dict.ToHandleChecked();
    1043             : 
    1044             :     // We couldn't add to the small table, let's migrate to the
    1045             :     // big table.
    1046             :     table =
    1047           5 :         OrderedNameDictionaryHandler::AdjustRepresentation(isolate, small_dict);
    1048             :   }
    1049             : 
    1050             :   DCHECK(table->IsOrderedNameDictionary());
    1051             :   return OrderedNameDictionary::Add(
    1052        3855 :       isolate, Handle<OrderedNameDictionary>::cast(table), key, value, details);
    1053             : }
    1054             : 
    1055           0 : void OrderedNameDictionaryHandler::SetEntry(Isolate* isolate, HeapObject table,
    1056             :                                             int entry, Object key, Object value,
    1057             :                                             PropertyDetails details) {
    1058             :   DisallowHeapAllocation no_gc;
    1059           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1060             :     return SmallOrderedNameDictionary::cast(table)->SetEntry(
    1061           0 :         isolate, entry, key, value, details);
    1062             :   }
    1063             : 
    1064             :   DCHECK(table->IsOrderedNameDictionary());
    1065             :   return OrderedNameDictionary::cast(table)->SetEntry(isolate, entry, key,
    1066           0 :                                                       value, details);
    1067             : }
    1068             : 
    1069     5242885 : int OrderedNameDictionaryHandler::FindEntry(Isolate* isolate, HeapObject table,
    1070             :                                             Name key) {
    1071             :   DisallowHeapAllocation no_gc;
    1072     5242885 :   if (table->IsSmallOrderedNameDictionary()) {
    1073             :     int entry =
    1074     1295365 :         SmallOrderedNameDictionary::cast(table)->FindEntry(isolate, key);
    1075             :     return entry == SmallOrderedNameDictionary::kNotFound
    1076             :                ? OrderedNameDictionaryHandler::kNotFound
    1077     1295365 :                : entry;
    1078             :   }
    1079             : 
    1080             :   DCHECK(table->IsOrderedNameDictionary());
    1081     3947520 :   int entry = OrderedNameDictionary::cast(table)->FindEntry(isolate, key);
    1082             :   return entry == OrderedNameDictionary::kNotFound
    1083             :              ? OrderedNameDictionaryHandler::kNotFound
    1084     3947520 :              : entry;
    1085             : }
    1086             : 
    1087           0 : Object OrderedNameDictionaryHandler::ValueAt(HeapObject table, int entry) {
    1088           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1089             :     return SmallOrderedNameDictionary::cast(table)->ValueAt(entry);
    1090             :   }
    1091             : 
    1092             :   DCHECK(table->IsOrderedNameDictionary());
    1093           0 :   return OrderedNameDictionary::cast(table)->ValueAt(entry);
    1094             : }
    1095             : 
    1096           0 : void OrderedNameDictionaryHandler::ValueAtPut(HeapObject table, int entry,
    1097             :                                               Object value) {
    1098           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1099           0 :     return SmallOrderedNameDictionary::cast(table)->ValueAtPut(entry, value);
    1100             :   }
    1101             : 
    1102             :   DCHECK(table->IsOrderedNameDictionary());
    1103           0 :   OrderedNameDictionary::cast(table)->ValueAtPut(entry, value);
    1104             : }
    1105             : 
    1106           0 : PropertyDetails OrderedNameDictionaryHandler::DetailsAt(HeapObject table,
    1107             :                                                         int entry) {
    1108           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1109           0 :     return SmallOrderedNameDictionary::cast(table)->DetailsAt(entry);
    1110             :   }
    1111             : 
    1112             :   DCHECK(table->IsOrderedNameDictionary());
    1113           0 :   return OrderedNameDictionary::cast(table)->DetailsAt(entry);
    1114             : }
    1115             : 
    1116           0 : void OrderedNameDictionaryHandler::DetailsAtPut(HeapObject table, int entry,
    1117             :                                                 PropertyDetails details) {
    1118           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1119             :     return SmallOrderedNameDictionary::cast(table)->DetailsAtPut(entry,
    1120           0 :                                                                  details);
    1121             :   }
    1122             : 
    1123             :   DCHECK(table->IsOrderedNameDictionary());
    1124           0 :   OrderedNameDictionary::cast(table)->DetailsAtPut(entry, details);
    1125             : }
    1126             : 
    1127           0 : int OrderedNameDictionaryHandler::Hash(HeapObject table) {
    1128           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1129             :     return SmallOrderedNameDictionary::cast(table)->Hash();
    1130             :   }
    1131             : 
    1132             :   DCHECK(table->IsOrderedNameDictionary());
    1133           0 :   return OrderedNameDictionary::cast(table)->Hash();
    1134             : }
    1135             : 
    1136           0 : void OrderedNameDictionaryHandler::SetHash(HeapObject table, int hash) {
    1137           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1138           0 :     return SmallOrderedNameDictionary::cast(table)->SetHash(hash);
    1139             :   }
    1140             : 
    1141             :   DCHECK(table->IsOrderedNameDictionary());
    1142             :   OrderedNameDictionary::cast(table)->SetHash(hash);
    1143             : }
    1144             : 
    1145           0 : Name OrderedNameDictionaryHandler::KeyAt(HeapObject table, int entry) {
    1146           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1147             :     return Name::cast(SmallOrderedNameDictionary::cast(table)->KeyAt(entry));
    1148             :   }
    1149             : 
    1150           0 :   return Name::cast(OrderedNameDictionary::cast(table)->KeyAt(entry));
    1151             : }
    1152             : 
    1153           0 : int OrderedNameDictionaryHandler::NumberOfElements(HeapObject table) {
    1154           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1155             :     return SmallOrderedNameDictionary::cast(table)->NumberOfElements();
    1156             :   }
    1157             : 
    1158           0 :   return OrderedNameDictionary::cast(table)->NumberOfElements();
    1159             : }
    1160             : 
    1161           5 : int OrderedNameDictionaryHandler::Capacity(HeapObject table) {
    1162           5 :   if (table->IsSmallOrderedNameDictionary()) {
    1163             :     return SmallOrderedNameDictionary::cast(table)->Capacity();
    1164             :   }
    1165             : 
    1166          10 :   return OrderedNameDictionary::cast(table)->Capacity();
    1167             : }
    1168             : 
    1169           0 : Handle<HeapObject> OrderedNameDictionaryHandler::Shrink(
    1170             :     Isolate* isolate, Handle<HeapObject> table) {
    1171           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1172             :     Handle<SmallOrderedNameDictionary> small_dict =
    1173           0 :         Handle<SmallOrderedNameDictionary>::cast(table);
    1174           0 :     return SmallOrderedNameDictionary::Shrink(isolate, small_dict);
    1175             :   }
    1176             : 
    1177             :   Handle<OrderedNameDictionary> large_dict =
    1178           0 :       Handle<OrderedNameDictionary>::cast(table);
    1179           0 :   return OrderedNameDictionary::Shrink(isolate, large_dict);
    1180             : }
    1181             : 
    1182           0 : Handle<HeapObject> OrderedNameDictionaryHandler::DeleteEntry(
    1183             :     Isolate* isolate, Handle<HeapObject> table, int entry) {
    1184             :   DisallowHeapAllocation no_gc;
    1185           0 :   if (table->IsSmallOrderedNameDictionary()) {
    1186             :     Handle<SmallOrderedNameDictionary> small_dict =
    1187           0 :         Handle<SmallOrderedNameDictionary>::cast(table);
    1188           0 :     return SmallOrderedNameDictionary::DeleteEntry(isolate, small_dict, entry);
    1189             :   }
    1190             : 
    1191             :   Handle<OrderedNameDictionary> large_dict =
    1192           0 :       Handle<OrderedNameDictionary>::cast(table);
    1193           0 :   return OrderedNameDictionary::DeleteEntry(isolate, large_dict, entry);
    1194             : }
    1195             : 
    1196             : template <class Derived, class TableType>
    1197         408 : void OrderedHashTableIterator<Derived, TableType>::Transition() {
    1198             :   DisallowHeapAllocation no_allocation;
    1199         816 :   TableType table = TableType::cast(this->table());
    1200         806 :   if (!table->IsObsolete()) return;
    1201             : 
    1202          10 :   int index = Smi::ToInt(this->index());
    1203          50 :   while (table->IsObsolete()) {
    1204          30 :     TableType next_table = table->NextTable();
    1205             : 
    1206          30 :     if (index > 0) {
    1207          30 :       int nod = table->NumberOfDeletedElements();
    1208             : 
    1209          30 :       if (nod == TableType::kClearedTableSentinel) {
    1210             :         index = 0;
    1211             :       } else {
    1212             :         int old_index = index;
    1213          10 :         for (int i = 0; i < nod; ++i) {
    1214          10 :           int removed_index = table->RemovedIndexAt(i);
    1215          10 :           if (removed_index >= old_index) break;
    1216          10 :           --index;
    1217             :         }
    1218             :       }
    1219             :     }
    1220             : 
    1221          30 :     table = next_table;
    1222             :   }
    1223             : 
    1224          10 :   set_table(table);
    1225          10 :   set_index(Smi::FromInt(index));
    1226             : }
    1227             : 
    1228             : template <class Derived, class TableType>
    1229         408 : bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
    1230             :   DisallowHeapAllocation no_allocation;
    1231         408 :   ReadOnlyRoots ro_roots = GetReadOnlyRoots();
    1232             : 
    1233         408 :   Transition();
    1234             : 
    1235         816 :   TableType table = TableType::cast(this->table());
    1236         408 :   int index = Smi::ToInt(this->index());
    1237         408 :   int used_capacity = table->UsedCapacity();
    1238             : 
    1239        1204 :   while (index < used_capacity && table->KeyAt(index)->IsTheHole(ro_roots)) {
    1240          20 :     index++;
    1241             :   }
    1242             : 
    1243         408 :   set_index(Smi::FromInt(index));
    1244             : 
    1245         408 :   if (index < used_capacity) return true;
    1246             : 
    1247          60 :   set_table(TableType::GetEmpty(ro_roots));
    1248          60 :   return false;
    1249             : }
    1250             : 
    1251             : template bool
    1252             : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
    1253             : 
    1254             : template void
    1255             : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
    1256             : 
    1257             : template Object
    1258             : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
    1259             : 
    1260             : template void
    1261             : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
    1262             : 
    1263             : template bool
    1264             : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
    1265             : 
    1266             : template void
    1267             : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
    1268             : 
    1269             : template Object
    1270             : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
    1271             : 
    1272             : template void
    1273             : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
    1274             : 
    1275             : }  // namespace internal
    1276      183867 : }  // namespace v8

Generated by: LCOV version 1.10