LCOV - code coverage report
Current view: top level - src/objects - ordered-hash-table.h (source / functions) Hit Total Coverage
Test: app.info Lines: 78 82 95.1 %
Date: 2019-02-19 Functions: 58 63 92.1 %

          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             : #ifndef V8_OBJECTS_ORDERED_HASH_TABLE_H_
       6             : #define V8_OBJECTS_ORDERED_HASH_TABLE_H_
       7             : 
       8             : #include "src/globals.h"
       9             : #include "src/objects/fixed-array.h"
      10             : #include "src/objects/js-objects.h"
      11             : #include "src/objects/smi.h"
      12             : #include "src/roots.h"
      13             : 
      14             : // Has to be the last include (doesn't have include guards):
      15             : #include "src/objects/object-macros.h"
      16             : 
      17             : namespace v8 {
      18             : namespace internal {
      19             : 
      20             : // OrderedHashTable is a HashTable with Object keys that preserves
      21             : // insertion order. There are Map and Set interfaces (OrderedHashMap
      22             : // and OrderedHashTable, below). It is meant to be used by JSMap/JSSet.
      23             : //
      24             : // Only Object keys are supported, with Object::SameValueZero() used as the
      25             : // equality operator and Object::GetHash() for the hash function.
      26             : //
      27             : // Based on the "Deterministic Hash Table" as described by Jason Orendorff at
      28             : // https://wiki.mozilla.org/User:Jorend/Deterministic_hash_tables
      29             : // Originally attributed to Tyler Close.
      30             : //
      31             : // Memory layout:
      32             : //   [0] : Prefix
      33             : //   [kPrefixSize]: element count
      34             : //   [kPrefixSize + 1]: deleted element count
      35             : //   [kPrefixSize + 2]: bucket count
      36             : //   [kPrefixSize + 3..(3 + NumberOfBuckets() - 1)]: "hash table",
      37             : //                            where each item is an offset into the
      38             : //                            data table (see below) where the first
      39             : //                            item in this bucket is stored.
      40             : //   [kPrefixSize + 3 + NumberOfBuckets()..length]: "data table", an
      41             : //                            array of length Capacity() * kEntrySize,
      42             : //                            where the first entrysize items are
      43             : //                            handled by the derived class and the
      44             : //                            item at kChainOffset is another entry
      45             : //                            into the data table indicating the next
      46             : //                            entry in this hash bucket.
      47             : //
      48             : // When we transition the table to a new version we obsolete it and reuse parts
      49             : // of the memory to store information how to transition an iterator to the new
      50             : // table:
      51             : //
      52             : // Memory layout for obsolete table:
      53             : //   [0] : Prefix
      54             : //   [kPrefixSize + 0]: bucket count
      55             : //   [kPrefixSize + 1]: Next newer table
      56             : //   [kPrefixSize + 2]: Number of removed holes or -1 when the table was
      57             : //                      cleared.
      58             : //   [kPrefixSize + 3..(3 + NumberOfRemovedHoles() - 1)]: The indexes
      59             : //                      of the removed holes.
      60             : //   [kPrefixSize + 3 + NumberOfRemovedHoles()..length]: Not used
      61             : template <class Derived, int entrysize>
      62             : class OrderedHashTable : public FixedArray {
      63             :  public:
      64             :   // Returns an OrderedHashTable (possibly |table|) with enough space
      65             :   // to add at least one new element.
      66             :   static Handle<Derived> EnsureGrowable(Isolate* isolate,
      67             :                                         Handle<Derived> table);
      68             : 
      69             :   // Returns an OrderedHashTable (possibly |table|) that's shrunken
      70             :   // if possible.
      71             :   static Handle<Derived> Shrink(Isolate* isolate, Handle<Derived> table);
      72             : 
      73             :   // Returns a new empty OrderedHashTable and records the clearing so that
      74             :   // existing iterators can be updated.
      75             :   static Handle<Derived> Clear(Isolate* isolate, Handle<Derived> table);
      76             : 
      77             :   // Returns true if the OrderedHashTable contains the key
      78             :   static bool HasKey(Isolate* isolate, Derived table, Object key);
      79             : 
      80             :   // Returns a true value if the OrderedHashTable contains the key and
      81             :   // the key has been deleted. This does not shrink the table.
      82             :   static bool Delete(Isolate* isolate, Derived table, Object key);
      83             : 
      84             :   int FindEntry(Isolate* isolate, Object key);
      85             : 
      86    21347906 :   int NumberOfElements() const {
      87    21347906 :     return Smi::ToInt(get(NumberOfElementsIndex()));
      88             :   }
      89             : 
      90    20813644 :   int NumberOfDeletedElements() const {
      91    20813644 :     return Smi::ToInt(get(NumberOfDeletedElementsIndex()));
      92             :   }
      93             : 
      94             :   // Returns the number of contiguous entries in the data table, starting at 0,
      95             :   // that either are real entries or have been deleted.
      96        1369 :   int UsedCapacity() const {
      97        1369 :     return NumberOfElements() + NumberOfDeletedElements();
      98             :   }
      99             : 
     100   181716534 :   int NumberOfBuckets() const {
     101   181716534 :     return Smi::ToInt(get(NumberOfBucketsIndex()));
     102             :   }
     103             : 
     104             :   // Returns an index into |this| for the given entry.
     105             :   int EntryToIndex(int entry) {
     106   131516467 :     return HashTableStartIndex() + NumberOfBuckets() + (entry * kEntrySize);
     107             :   }
     108             : 
     109    39033764 :   int HashToBucket(int hash) { return hash & (NumberOfBuckets() - 1); }
     110             : 
     111    28976879 :   int HashToEntry(int hash) {
     112             :     int bucket = HashToBucket(hash);
     113    57953758 :     Object entry = this->get(HashTableStartIndex() + bucket);
     114    28976879 :     return Smi::ToInt(entry);
     115             :   }
     116             : 
     117    21062420 :   int NextChainEntry(int entry) {
     118    42124840 :     Object next_entry = get(EntryToIndex(entry) + kChainOffset);
     119    21062420 :     return Smi::ToInt(next_entry);
     120             :   }
     121             : 
     122             :   // use KeyAt(i)->IsTheHole(isolate) to determine if this is a deleted entry.
     123    52606644 :   Object KeyAt(int entry) {
     124             :     DCHECK_LT(entry, this->UsedCapacity());
     125    52606644 :     return get(EntryToIndex(entry));
     126             :   }
     127             : 
     128        1554 :   bool IsObsolete() { return !get(NextTableIndex())->IsSmi(); }
     129             : 
     130             :   // The next newer table. This is only valid if the table is obsolete.
     131          90 :   Derived NextTable() { return Derived::cast(get(NextTableIndex())); }
     132             : 
     133             :   // When the table is obsolete we store the indexes of the removed holes.
     134          15 :   int RemovedIndexAt(int index) {
     135          30 :     return Smi::ToInt(get(RemovedHolesIndex() + index));
     136             :   }
     137             : 
     138             :   // The extra +1 is for linking the bucket chains together.
     139             :   static const int kEntrySize = entrysize + 1;
     140             :   static const int kChainOffset = entrysize;
     141             : 
     142             :   static const int kNotFound = -1;
     143             :   static const int kMinCapacity = 4;
     144             : 
     145             :   static constexpr int PrefixIndex() { return 0; }
     146             : 
     147       12152 :   static constexpr int NumberOfElementsIndex() { return Derived::kPrefixSize; }
     148             : 
     149             :   // The next table is stored at the same index as the nof elements.
     150         672 :   static constexpr int NextTableIndex() { return NumberOfElementsIndex(); }
     151             : 
     152       10136 :   static constexpr int NumberOfDeletedElementsIndex() {
     153       10136 :     return NumberOfElementsIndex() + 1;
     154             :   }
     155             : 
     156        9184 :   static constexpr int NumberOfBucketsIndex() {
     157        9184 :     return NumberOfDeletedElementsIndex() + 1;
     158             :   }
     159             : 
     160        6720 :   static constexpr int HashTableStartIndex() {
     161        6720 :     return NumberOfBucketsIndex() + 1;
     162             :   }
     163             : 
     164          56 :   static constexpr int RemovedHolesIndex() { return HashTableStartIndex(); }
     165             : 
     166        1232 :   static constexpr int NumberOfElementsOffset() {
     167        1232 :     return FixedArray::OffsetOfElementAt(NumberOfElementsIndex());
     168             :   }
     169             : 
     170         672 :   static constexpr int NextTableOffset() {
     171         672 :     return FixedArray::OffsetOfElementAt(NextTableIndex());
     172             :   }
     173             : 
     174         840 :   static constexpr int NumberOfDeletedElementsOffset() {
     175         840 :     return FixedArray::OffsetOfElementAt(NumberOfDeletedElementsIndex());
     176             :   }
     177             : 
     178         336 :   static constexpr int NumberOfBucketsOffset() {
     179         336 :     return FixedArray::OffsetOfElementAt(NumberOfBucketsIndex());
     180             :   }
     181             : 
     182             :   static constexpr int HashTableStartOffset() {
     183             :     return FixedArray::OffsetOfElementAt(HashTableStartIndex());
     184             :   }
     185             : 
     186             :   static const int kLoadFactor = 2;
     187             : 
     188             :   // NumberOfDeletedElements is set to kClearedTableSentinel when
     189             :   // the table is cleared, which allows iterator transitions to
     190             :   // optimize that case.
     191             :   static const int kClearedTableSentinel = -1;
     192             :   static constexpr int MaxCapacity() {
     193             :     return (FixedArray::kMaxLength - HashTableStartIndex()) /
     194             :            (1 + (kEntrySize * kLoadFactor));
     195             :   }
     196             : 
     197             :  protected:
     198             :   // Returns an OrderedHashTable with a capacity of at least |capacity|.
     199             :   static Handle<Derived> Allocate(Isolate* isolate, int capacity,
     200             :                                   PretenureFlag pretenure = NOT_TENURED);
     201             :   static Handle<Derived> Rehash(Isolate* isolate, Handle<Derived> table,
     202             :                                 int new_capacity);
     203             : 
     204             :   void SetNumberOfBuckets(int num) {
     205             :     set(NumberOfBucketsIndex(), Smi::FromInt(num));
     206             :   }
     207             : 
     208             :   void SetNumberOfElements(int num) {
     209             :     set(NumberOfElementsIndex(), Smi::FromInt(num));
     210             :   }
     211             : 
     212             :   void SetNumberOfDeletedElements(int num) {
     213             :     set(NumberOfDeletedElementsIndex(), Smi::FromInt(num));
     214             :   }
     215             : 
     216             :   // Returns the number elements that can fit into the allocated buffer.
     217    10389379 :   int Capacity() { return NumberOfBuckets() * kLoadFactor; }
     218             : 
     219      527892 :   void SetNextTable(Derived next_table) { set(NextTableIndex(), next_table); }
     220             : 
     221      243554 :   void SetRemovedIndexAt(int index, int removed_index) {
     222      243554 :     return set(RemovedHolesIndex() + index, Smi::FromInt(removed_index));
     223             :   }
     224             : 
     225             :   OBJECT_CONSTRUCTORS(OrderedHashTable, FixedArray);
     226             : 
     227             :  private:
     228             :   friend class OrderedNameDictionaryHandler;
     229             : };
     230             : 
     231             : class OrderedHashSet : public OrderedHashTable<OrderedHashSet, 1> {
     232             :  public:
     233             :   DECL_CAST(OrderedHashSet)
     234             : 
     235             :   static Handle<OrderedHashSet> Add(Isolate* isolate,
     236             :                                     Handle<OrderedHashSet> table,
     237             :                                     Handle<Object> value);
     238             :   static Handle<FixedArray> ConvertToKeysArray(Isolate* isolate,
     239             :                                                Handle<OrderedHashSet> table,
     240             :                                                GetKeysConversion convert);
     241             :   static Handle<OrderedHashSet> Rehash(Isolate* isolate,
     242             :                                        Handle<OrderedHashSet> table,
     243             :                                        int new_capacity);
     244             :   static Handle<OrderedHashSet> Allocate(Isolate* isolate, int capacity,
     245             :                                          PretenureFlag pretenure = NOT_TENURED);
     246             :   static HeapObject GetEmpty(ReadOnlyRoots ro_roots);
     247             :   static inline RootIndex GetMapRootIndex();
     248             :   static inline bool Is(Handle<HeapObject> table);
     249             :   static const int kPrefixSize = 0;
     250             : 
     251             :   OBJECT_CONSTRUCTORS(OrderedHashSet, OrderedHashTable<OrderedHashSet, 1>);
     252             : };
     253             : 
     254             : class OrderedHashMap : public OrderedHashTable<OrderedHashMap, 2> {
     255             :  public:
     256             :   DECL_CAST(OrderedHashMap)
     257             : 
     258             :   // Returns a value if the OrderedHashMap contains the key, otherwise
     259             :   // returns undefined.
     260             :   static Handle<OrderedHashMap> Add(Isolate* isolate,
     261             :                                     Handle<OrderedHashMap> table,
     262             :                                     Handle<Object> key, Handle<Object> value);
     263             : 
     264             :   static Handle<OrderedHashMap> Allocate(Isolate* isolate, int capacity,
     265             :                                          PretenureFlag pretenure = NOT_TENURED);
     266             :   static Handle<OrderedHashMap> Rehash(Isolate* isolate,
     267             :                                        Handle<OrderedHashMap> table,
     268             :                                        int new_capacity);
     269             :   Object ValueAt(int entry);
     270             : 
     271             :   // This takes and returns raw Address values containing tagged Object
     272             :   // pointers because it is called via ExternalReference.
     273             :   static Address GetHash(Isolate* isolate, Address raw_key);
     274             : 
     275             :   static HeapObject GetEmpty(ReadOnlyRoots ro_roots);
     276             :   static inline RootIndex GetMapRootIndex();
     277             :   static inline bool Is(Handle<HeapObject> table);
     278             : 
     279             :   static const int kValueOffset = 1;
     280             :   static const int kPrefixSize = 0;
     281             : 
     282             :   OBJECT_CONSTRUCTORS(OrderedHashMap, OrderedHashTable<OrderedHashMap, 2>);
     283             : };
     284             : 
     285             : // This is similar to the OrderedHashTable, except for the memory
     286             : // layout where we use byte instead of Smi. The max capacity of this
     287             : // is only 254, we transition to an OrderedHashTable beyond that
     288             : // limit.
     289             : //
     290             : // Each bucket and chain value is a byte long. The padding exists so
     291             : // that the DataTable entries start aligned. A bucket or chain value
     292             : // of 255 is used to denote an unknown entry.
     293             : //
     294             : // The prefix size is calculated as the kPrefixSize * kTaggedSize.
     295             : //
     296             : // Memory layout: [ Prefix ] [ Header ]  [ Padding ] [ DataTable ] [ HashTable ]
     297             : // [ Chains ]
     298             : //
     299             : // The index are represented as bytes, on a 64 bit machine with
     300             : // kEntrySize = 1, capacity = 4 and entries = 2:
     301             : //
     302             : // [ 0 ] : Prefix
     303             : //
     304             : // Note: For the sake of brevity, the following start with index 0
     305             : // but, they actually start from kPrefixSize * kTaggedSize to
     306             : // account for the the prefix.
     307             : //
     308             : // [ Header ]  :
     309             : //    [0] : Number of elements
     310             : //    [1] : Number of deleted elements
     311             : //    [2] : Number of buckets
     312             : //
     313             : // [ Padding ] :
     314             : //    [3 .. 7] : Padding
     315             : //
     316             : // [ DataTable ] :
     317             : //    [8  .. 15] : Entry 1
     318             : //    [16 .. 23] : Entry 2
     319             : //    [24 .. 31] : empty
     320             : //    [32 .. 39] : empty
     321             : //
     322             : // [ HashTable ] :
     323             : //    [40] : First chain-link for bucket 1
     324             : //    [41] : empty
     325             : //
     326             : // [ Chains ] :
     327             : //    [42] : Next chain link for bucket 1
     328             : //    [43] : empty
     329             : //    [44] : empty
     330             : //    [45] : empty
     331             : //
     332             : template <class Derived>
     333             : class SmallOrderedHashTable : public HeapObject {
     334             :  public:
     335             :   // Offset points to a relative location in the table
     336             :   typedef int Offset;
     337             : 
     338             :   // ByteIndex points to a index in the table that needs to be
     339             :   // converted to an Offset.
     340             :   typedef int ByteIndex;
     341             : 
     342             :   void Initialize(Isolate* isolate, int capacity);
     343             : 
     344             :   static Handle<Derived> Allocate(Isolate* isolate, int capacity,
     345             :                                   PretenureFlag pretenure = NOT_TENURED);
     346             : 
     347             :   // Returns a true if the OrderedHashTable contains the key
     348             :   bool HasKey(Isolate* isolate, Handle<Object> key);
     349             : 
     350             :   // Returns a true value if the table contains the key and
     351             :   // the key has been deleted. This does not shrink the table.
     352             :   static bool Delete(Isolate* isolate, Derived table, Object key);
     353             : 
     354             :   // Returns an SmallOrderedHashTable (possibly |table|) with enough
     355             :   // space to add at least one new element. Returns empty handle if
     356             :   // we've already reached MaxCapacity.
     357             :   static MaybeHandle<Derived> Grow(Isolate* isolate, Handle<Derived> table);
     358             : 
     359             :   int FindEntry(Isolate* isolate, Object key);
     360             :   static Handle<Derived> Shrink(Isolate* isolate, Handle<Derived> table);
     361             : 
     362             :   // Iterates only fields in the DataTable.
     363             :   class BodyDescriptor;
     364             : 
     365             :   // Returns total size in bytes required for a table of given
     366             :   // capacity.
     367             :   static int SizeFor(int capacity) {
     368             :     DCHECK_GE(capacity, kMinCapacity);
     369             :     DCHECK_LE(capacity, kMaxCapacity);
     370             : 
     371             :     int data_table_size = DataTableSizeFor(capacity);
     372         443 :     int hash_table_size = capacity / kLoadFactor;
     373             :     int chain_table_size = capacity;
     374             :     int total_size = DataTableStartOffset() + data_table_size +
     375         491 :                      hash_table_size + chain_table_size;
     376             : 
     377             :     return RoundUp(total_size, kTaggedSize);
     378             :   }
     379             : 
     380             :   // Returns the number elements that can fit into the allocated table.
     381             :   int Capacity() const {
     382     1686888 :     int capacity = NumberOfBuckets() * kLoadFactor;
     383             :     DCHECK_GE(capacity, kMinCapacity);
     384             :     DCHECK_LE(capacity, kMaxCapacity);
     385             : 
     386             :     return capacity;
     387             :   }
     388             : 
     389             :   // Returns the number elements that are present in the table.
     390             :   int NumberOfElements() const {
     391       23575 :     int nof_elements = getByte(NumberOfElementsOffset(), 0);
     392             :     DCHECK_LE(nof_elements, Capacity());
     393             : 
     394             :     return nof_elements;
     395             :   }
     396             : 
     397             :   int NumberOfDeletedElements() const {
     398       22570 :     int nof_deleted_elements = getByte(NumberOfDeletedElementsOffset(), 0);
     399             :     DCHECK_LE(nof_deleted_elements, Capacity());
     400             : 
     401             :     return nof_deleted_elements;
     402             :   }
     403             : 
     404     2150536 :   int NumberOfBuckets() const { return getByte(NumberOfBucketsOffset(), 0); }
     405             : 
     406             :   Object KeyAt(int entry) const {
     407             :     DCHECK_LT(entry, Capacity());
     408             :     Offset entry_offset = GetDataEntryOffset(entry, Derived::kKeyIndex);
     409     3602865 :     return READ_FIELD(*this, entry_offset);
     410             :   }
     411             : 
     412             :   DECL_VERIFIER(SmallOrderedHashTable)
     413             : 
     414             :   static const int kMinCapacity = 4;
     415             :   static const byte kNotFound = 0xFF;
     416             : 
     417             :   // We use the value 255 to indicate kNotFound for chain and bucket
     418             :   // values, which means that this value can't be used a valid
     419             :   // index.
     420             :   static const int kMaxCapacity = 254;
     421             :   STATIC_ASSERT(kMaxCapacity < kNotFound);
     422             : 
     423             :   // The load factor is used to derive the number of buckets from
     424             :   // capacity during Allocation. We also depend on this to calaculate
     425             :   // the capacity from number of buckets after allocation. If we
     426             :   // decide to change kLoadFactor to something other than 2, capacity
     427             :   // should be stored as another field of this object.
     428             :   static const int kLoadFactor = 2;
     429             : 
     430             :   // Our growth strategy involves doubling the capacity until we reach
     431             :   // kMaxCapacity, but since the kMaxCapacity is always less than 256,
     432             :   // we will never fully utilize this table. We special case for 256,
     433             :   // by changing the new capacity to be kMaxCapacity in
     434             :   // SmallOrderedHashTable::Grow.
     435             :   static const int kGrowthHack = 256;
     436             : 
     437             :  protected:
     438             :   static Handle<Derived> Rehash(Isolate* isolate, Handle<Derived> table,
     439             :                                 int new_capacity);
     440             : 
     441             :   void SetDataEntry(int entry, int relative_index, Object value);
     442             : 
     443             :   // TODO(gsathya): Calculate all the various possible values for this
     444             :   // at compile time since capacity can only be 4 different values.
     445             :   Offset GetBucketsStartOffset() const {
     446             :     int capacity = Capacity();
     447             :     int data_table_size = DataTableSizeFor(capacity);
     448     1674940 :     return DataTableStartOffset() + data_table_size;
     449             :   }
     450             : 
     451             :   Address GetHashTableStartAddress(int capacity) const {
     452         886 :     return FIELD_ADDR(*this,
     453             :                       DataTableStartOffset() + DataTableSizeFor(capacity));
     454             :   }
     455             : 
     456             :   void SetFirstEntry(int bucket, byte value) {
     457             :     DCHECK_LE(static_cast<unsigned>(bucket), NumberOfBuckets());
     458             :     setByte(GetBucketsStartOffset(), bucket, value);
     459             :   }
     460             : 
     461             :   int GetFirstEntry(int bucket) const {
     462             :     DCHECK_LE(static_cast<unsigned>(bucket), NumberOfBuckets());
     463     1653935 :     return getByte(GetBucketsStartOffset(), bucket);
     464             :   }
     465             : 
     466             :   // TODO(gsathya): Calculate all the various possible values for this
     467             :   // at compile time since capacity can only be 4 different values.
     468             :   Offset GetChainTableOffset() const {
     469             :     int nof_buckets = NumberOfBuckets();
     470      442595 :     int capacity = nof_buckets * kLoadFactor;
     471             :     DCHECK_EQ(Capacity(), capacity);
     472             : 
     473             :     int data_table_size = DataTableSizeFor(capacity);
     474             :     int hash_table_size = nof_buckets;
     475     3116625 :     return DataTableStartOffset() + data_table_size + hash_table_size;
     476             :   }
     477             : 
     478             :   void SetNextEntry(int entry, int next_entry) {
     479             :     DCHECK_LT(static_cast<unsigned>(entry), Capacity());
     480             :     DCHECK_GE(static_cast<unsigned>(next_entry), 0);
     481             :     DCHECK(next_entry <= Capacity() || next_entry == kNotFound);
     482       21005 :     setByte(GetChainTableOffset(), entry, next_entry);
     483             :   }
     484             : 
     485             :   int GetNextEntry(int entry) const {
     486             :     DCHECK_LT(entry, Capacity());
     487     3095620 :     return getByte(GetChainTableOffset(), entry);
     488             :   }
     489             : 
     490             :   Object GetDataEntry(int entry, int relative_index) {
     491             :     DCHECK_LT(entry, Capacity());
     492             :     DCHECK_LE(static_cast<unsigned>(relative_index), Derived::kEntrySize);
     493             :     Offset entry_offset = GetDataEntryOffset(entry, relative_index);
     494       28335 :     return READ_FIELD(*this, entry_offset);
     495             :   }
     496             : 
     497     1664265 :   int HashToBucket(int hash) const { return hash & (NumberOfBuckets() - 1); }
     498             : 
     499             :   int HashToFirstEntry(int hash) const {
     500             :     int bucket = HashToBucket(hash);
     501             :     int entry = GetFirstEntry(bucket);
     502             :     DCHECK(entry < Capacity() || entry == kNotFound);
     503             :     return entry;
     504             :   }
     505             : 
     506         443 :   void SetNumberOfBuckets(int num) { setByte(NumberOfBucketsOffset(), 0, num); }
     507             : 
     508             :   void SetNumberOfElements(int num) {
     509             :     DCHECK_LE(static_cast<unsigned>(num), Capacity());
     510       11935 :     setByte(NumberOfElementsOffset(), 0, num);
     511             :   }
     512             : 
     513             :   void SetNumberOfDeletedElements(int num) {
     514             :     DCHECK_LE(static_cast<unsigned>(num), Capacity());
     515        1315 :     setByte(NumberOfDeletedElementsOffset(), 0, num);
     516             :   }
     517             : 
     518          32 :   static constexpr Offset PrefixOffset() { return kHeaderSize; }
     519             : 
     520          32 :   static constexpr Offset NumberOfElementsOffset() {
     521          32 :     return PrefixOffset() + (Derived::kPrefixSize * kTaggedSize);
     522             :   }
     523             : 
     524          24 :   static constexpr Offset NumberOfDeletedElementsOffset() {
     525          24 :     return NumberOfElementsOffset() + kOneByteSize;
     526             :   }
     527             : 
     528          16 :   static constexpr Offset NumberOfBucketsOffset() {
     529          16 :     return NumberOfDeletedElementsOffset() + kOneByteSize;
     530             :   }
     531             : 
     532           8 :   static constexpr Offset DataTableStartOffset() {
     533           8 :     return RoundUp<kTaggedSize>(NumberOfBucketsOffset());
     534             :   }
     535             : 
     536             :   static constexpr int DataTableSizeFor(int capacity) {
     537     2118469 :     return capacity * Derived::kEntrySize * kTaggedSize;
     538             :   }
     539             : 
     540             :   // This is used for accessing the non |DataTable| part of the
     541             :   // structure.
     542             :   byte getByte(Offset offset, ByteIndex index) const {
     543             :     DCHECK(offset < DataTableStartOffset() ||
     544             :            offset >= GetBucketsStartOffset());
     545     6947412 :     return READ_BYTE_FIELD(*this, offset + (index * kOneByteSize));
     546             :   }
     547             : 
     548             :   void setByte(Offset offset, ByteIndex index, byte value) {
     549             :     DCHECK(offset < DataTableStartOffset() ||
     550             :            offset >= GetBucketsStartOffset());
     551       56589 :     WRITE_BYTE_FIELD(*this, offset + (index * kOneByteSize), value);
     552             :   }
     553             : 
     554             :   Offset GetDataEntryOffset(int entry, int relative_index) const {
     555             :     DCHECK_LT(entry, Capacity());
     556     3655765 :     int offset_in_datatable = entry * Derived::kEntrySize * kTaggedSize;
     557       76040 :     int offset_in_entry = relative_index * kTaggedSize;
     558     3682775 :     return DataTableStartOffset() + offset_in_datatable + offset_in_entry;
     559             :   }
     560             : 
     561             :   int UsedCapacity() const {
     562       10350 :     int used = NumberOfElements() + NumberOfDeletedElements();
     563             :     DCHECK_LE(used, Capacity());
     564             : 
     565             :     return used;
     566             :   }
     567             : 
     568             :  private:
     569             :   friend class OrderedHashMapHandler;
     570             :   friend class OrderedHashSetHandler;
     571             :   friend class OrderedNameDictionaryHandler;
     572             :   friend class CodeStubAssembler;
     573             : 
     574             :   OBJECT_CONSTRUCTORS(SmallOrderedHashTable, HeapObject);
     575             : };
     576             : 
     577             : class SmallOrderedHashSet : public SmallOrderedHashTable<SmallOrderedHashSet> {
     578             :  public:
     579             :   DECL_CAST(SmallOrderedHashSet)
     580             : 
     581             :   DECL_PRINTER(SmallOrderedHashSet)
     582             :   DECL_VERIFIER(SmallOrderedHashSet)
     583             : 
     584             :   static const int kKeyIndex = 0;
     585             :   static const int kEntrySize = 1;
     586             :   static const int kPrefixSize = 0;
     587             : 
     588             :   // Adds |value| to |table|, if the capacity isn't enough, a new
     589             :   // table is created. The original |table| is returned if there is
     590             :   // capacity to store |value| otherwise the new table is returned.
     591             :   static MaybeHandle<SmallOrderedHashSet> Add(Isolate* isolate,
     592             :                                               Handle<SmallOrderedHashSet> table,
     593             :                                               Handle<Object> key);
     594             :   static inline bool Is(Handle<HeapObject> table);
     595             :   static inline RootIndex GetMapRootIndex();
     596             :   static Handle<SmallOrderedHashSet> Rehash(Isolate* isolate,
     597             :                                             Handle<SmallOrderedHashSet> table,
     598             :                                             int new_capacity);
     599           0 :   OBJECT_CONSTRUCTORS(SmallOrderedHashSet,
     600             :                       SmallOrderedHashTable<SmallOrderedHashSet>);
     601             : };
     602             : 
     603             : class SmallOrderedHashMap : public SmallOrderedHashTable<SmallOrderedHashMap> {
     604             :  public:
     605             :   DECL_CAST(SmallOrderedHashMap)
     606             : 
     607             :   DECL_PRINTER(SmallOrderedHashMap)
     608             :   DECL_VERIFIER(SmallOrderedHashMap)
     609             : 
     610             :   static const int kKeyIndex = 0;
     611             :   static const int kValueIndex = 1;
     612             :   static const int kEntrySize = 2;
     613             :   static const int kPrefixSize = 0;
     614             : 
     615             :   // Adds |value| to |table|, if the capacity isn't enough, a new
     616             :   // table is created. The original |table| is returned if there is
     617             :   // capacity to store |value| otherwise the new table is returned.
     618             :   static MaybeHandle<SmallOrderedHashMap> Add(Isolate* isolate,
     619             :                                               Handle<SmallOrderedHashMap> table,
     620             :                                               Handle<Object> key,
     621             :                                               Handle<Object> value);
     622             :   static inline bool Is(Handle<HeapObject> table);
     623             :   static inline RootIndex GetMapRootIndex();
     624             : 
     625             :   static Handle<SmallOrderedHashMap> Rehash(Isolate* isolate,
     626             :                                             Handle<SmallOrderedHashMap> table,
     627             :                                             int new_capacity);
     628             : 
     629           0 :   OBJECT_CONSTRUCTORS(SmallOrderedHashMap,
     630             :                       SmallOrderedHashTable<SmallOrderedHashMap>);
     631             : };
     632             : 
     633             : // TODO(gsathya): Rename this to OrderedHashTable, after we rename
     634             : // OrderedHashTable to LargeOrderedHashTable. Also set up a
     635             : // OrderedHashSetBase class as a base class for the two tables and use
     636             : // that instead of a HeapObject here.
     637             : template <class SmallTable, class LargeTable>
     638             : class OrderedHashTableHandler {
     639             :  public:
     640             :   typedef int Entry;
     641             : 
     642             :   static Handle<HeapObject> Allocate(Isolate* isolate, int capacity);
     643             :   static bool Delete(Handle<HeapObject> table, Handle<Object> key);
     644             :   static bool HasKey(Isolate* isolate, Handle<HeapObject> table,
     645             :                      Handle<Object> key);
     646             : 
     647             :   // TODO(gsathya): Move this to OrderedHashTable
     648             :   static const int OrderedHashTableMinSize =
     649             :       SmallOrderedHashTable<SmallTable>::kGrowthHack << 1;
     650             : };
     651             : 
     652             : class OrderedHashMapHandler
     653             :     : public OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap> {
     654             :  public:
     655             :   static Handle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
     656             :                                 Handle<Object> key, Handle<Object> value);
     657             :   static Handle<OrderedHashMap> AdjustRepresentation(
     658             :       Isolate* isolate, Handle<SmallOrderedHashMap> table);
     659             : };
     660             : 
     661             : class OrderedHashSetHandler
     662             :     : public OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet> {
     663             :  public:
     664             :   static Handle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
     665             :                                 Handle<Object> key);
     666             :   static Handle<OrderedHashSet> AdjustRepresentation(
     667             :       Isolate* isolate, Handle<SmallOrderedHashSet> table);
     668             : };
     669             : 
     670             : class OrderedNameDictionary
     671             :     : public OrderedHashTable<OrderedNameDictionary, 3> {
     672             :  public:
     673             :   DECL_CAST(OrderedNameDictionary)
     674             : 
     675             :   static Handle<OrderedNameDictionary> Add(Isolate* isolate,
     676             :                                            Handle<OrderedNameDictionary> table,
     677             :                                            Handle<Name> key,
     678             :                                            Handle<Object> value,
     679             :                                            PropertyDetails details);
     680             : 
     681             :   void SetEntry(Isolate* isolate, int entry, Object key, Object value,
     682             :                 PropertyDetails details);
     683             : 
     684             :   static Handle<OrderedNameDictionary> DeleteEntry(
     685             :       Isolate* isolate, Handle<OrderedNameDictionary> table, int entry);
     686             : 
     687             :   static Handle<OrderedNameDictionary> Allocate(
     688             :       Isolate* isolate, int capacity, PretenureFlag pretenure = NOT_TENURED);
     689             : 
     690             :   static Handle<OrderedNameDictionary> Rehash(
     691             :       Isolate* isolate, Handle<OrderedNameDictionary> table, int new_capacity);
     692             : 
     693             :   // Returns the value for entry.
     694             :   inline Object ValueAt(int entry);
     695             : 
     696             :   // Set the value for entry.
     697             :   inline void ValueAtPut(int entry, Object value);
     698             : 
     699             :   // Returns the property details for the property at entry.
     700             :   inline PropertyDetails DetailsAt(int entry);
     701             : 
     702             :   // Set the details for entry.
     703             :   inline void DetailsAtPut(int entry, PropertyDetails value);
     704             : 
     705             :   inline void SetHash(int hash);
     706             :   inline int Hash();
     707             : 
     708             :   static HeapObject GetEmpty(ReadOnlyRoots ro_roots);
     709             :   static inline RootIndex GetMapRootIndex();
     710             : 
     711             :   static const int kValueOffset = 1;
     712             :   static const int kPropertyDetailsOffset = 2;
     713             :   static const int kPrefixSize = 1;
     714             : 
     715             :   OBJECT_CONSTRUCTORS(OrderedNameDictionary,
     716             :                       OrderedHashTable<OrderedNameDictionary, 3>);
     717             : };
     718             : 
     719             : class OrderedNameDictionaryHandler
     720             :     : public OrderedHashTableHandler<SmallOrderedNameDictionary,
     721             :                                      OrderedNameDictionary> {
     722             :  public:
     723             :   static Handle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
     724             :                                 Handle<Name> key, Handle<Object> value,
     725             :                                 PropertyDetails details);
     726             :   static Handle<HeapObject> Shrink(Isolate* isolate, Handle<HeapObject> table);
     727             : 
     728             :   static Handle<HeapObject> DeleteEntry(Isolate* isolate,
     729             :                                         Handle<HeapObject> table, int entry);
     730             :   static int FindEntry(Isolate* isolate, HeapObject table, Name key);
     731             :   static void SetEntry(Isolate* isolate, HeapObject table, int entry,
     732             :                        Object key, Object value, PropertyDetails details);
     733             : 
     734             :   // Returns the value for entry.
     735             :   static Object ValueAt(HeapObject table, int entry);
     736             : 
     737             :   // Set the value for entry.
     738             :   static void ValueAtPut(HeapObject table, int entry, Object value);
     739             : 
     740             :   // Returns the property details for the property at entry.
     741             :   static PropertyDetails DetailsAt(HeapObject table, int entry);
     742             : 
     743             :   // Set the details for entry.
     744             :   static void DetailsAtPut(HeapObject table, int entry, PropertyDetails value);
     745             : 
     746             :   static Name KeyAt(HeapObject table, int entry);
     747             : 
     748             :   static void SetHash(HeapObject table, int hash);
     749             :   static int Hash(HeapObject table);
     750             : 
     751             :   static int NumberOfElements(HeapObject table);
     752             :   static int Capacity(HeapObject table);
     753             : 
     754             :   static const int kNotFound = -1;
     755             : 
     756             :  protected:
     757             :   static Handle<OrderedNameDictionary> AdjustRepresentation(
     758             :       Isolate* isolate, Handle<SmallOrderedNameDictionary> table);
     759             : };
     760             : 
     761             : class SmallOrderedNameDictionary
     762             :     : public SmallOrderedHashTable<SmallOrderedNameDictionary> {
     763             :  public:
     764             :   DECL_CAST(SmallOrderedNameDictionary)
     765             : 
     766             :   DECL_PRINTER(SmallOrderedNameDictionary)
     767             :   DECL_VERIFIER(SmallOrderedNameDictionary)
     768             : 
     769             :   // Returns the value for entry.
     770             :   inline Object ValueAt(int entry);
     771             : 
     772             :   static Handle<SmallOrderedNameDictionary> Rehash(
     773             :       Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
     774             :       int new_capacity);
     775             : 
     776             :   static Handle<SmallOrderedNameDictionary> DeleteEntry(
     777             :       Isolate* isolate, Handle<SmallOrderedNameDictionary> table, int entry);
     778             : 
     779             :   // Set the value for entry.
     780             :   inline void ValueAtPut(int entry, Object value);
     781             : 
     782             :   // Returns the property details for the property at entry.
     783             :   inline PropertyDetails DetailsAt(int entry);
     784             : 
     785             :   // Set the details for entry.
     786             :   inline void DetailsAtPut(int entry, PropertyDetails value);
     787             : 
     788             :   inline void SetHash(int hash);
     789             :   inline int Hash();
     790             : 
     791             :   static const int kKeyIndex = 0;
     792             :   static const int kValueIndex = 1;
     793             :   static const int kPropertyDetailsIndex = 2;
     794             :   static const int kEntrySize = 3;
     795             :   static const int kPrefixSize = 1;
     796             : 
     797             :   // Adds |value| to |table|, if the capacity isn't enough, a new
     798             :   // table is created. The original |table| is returned if there is
     799             :   // capacity to store |value| otherwise the new table is returned.
     800             :   static MaybeHandle<SmallOrderedNameDictionary> Add(
     801             :       Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
     802             :       Handle<Name> key, Handle<Object> value, PropertyDetails details);
     803             : 
     804             :   void SetEntry(Isolate* isolate, int entry, Object key, Object value,
     805             :                 PropertyDetails details);
     806             : 
     807             :   static inline RootIndex GetMapRootIndex();
     808             : 
     809           0 :   OBJECT_CONSTRUCTORS(SmallOrderedNameDictionary,
     810             :                       SmallOrderedHashTable<SmallOrderedNameDictionary>);
     811             : };
     812             : 
     813             : class JSCollectionIterator : public JSObject {
     814             :  public:
     815             :   // [table]: the backing hash table mapping keys to values.
     816             :   DECL_ACCESSORS(table, Object)
     817             : 
     818             :   // [index]: The index into the data table.
     819             :   DECL_ACCESSORS(index, Object)
     820             : 
     821             :   void JSCollectionIteratorPrint(std::ostream& os, const char* name);
     822             : 
     823             : // Layout description.
     824             : #define JS_COLLECTION_ITERATOR_FIELDS(V) \
     825             :   V(kTableOffset, kTaggedSize)           \
     826             :   V(kIndexOffset, kTaggedSize)           \
     827             :   /* Header size. */                     \
     828             :   V(kSize, 0)
     829             : 
     830             :   DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
     831             :                                 JS_COLLECTION_ITERATOR_FIELDS)
     832             : #undef JS_COLLECTION_ITERATOR_FIELDS
     833             : 
     834             :   OBJECT_CONSTRUCTORS(JSCollectionIterator, JSObject);
     835             : };
     836             : 
     837             : // OrderedHashTableIterator is an iterator that iterates over the keys and
     838             : // values of an OrderedHashTable.
     839             : //
     840             : // The iterator has a reference to the underlying OrderedHashTable data,
     841             : // [table], as well as the current [index] the iterator is at.
     842             : //
     843             : // When the OrderedHashTable is rehashed it adds a reference from the old table
     844             : // to the new table as well as storing enough data about the changes so that the
     845             : // iterator [index] can be adjusted accordingly.
     846             : //
     847             : // When the [Next] result from the iterator is requested, the iterator checks if
     848             : // there is a newer table that it needs to transition to.
     849             : template <class Derived, class TableType>
     850             : class OrderedHashTableIterator : public JSCollectionIterator {
     851             :  public:
     852             :   // Whether the iterator has more elements. This needs to be called before
     853             :   // calling |CurrentKey| and/or |CurrentValue|.
     854             :   bool HasMore();
     855             : 
     856             :   // Move the index forward one.
     857           0 :   void MoveNext() { set_index(Smi::FromInt(Smi::ToInt(index()) + 1)); }
     858             : 
     859             :   // Returns the current key of the iterator. This should only be called when
     860             :   // |HasMore| returns true.
     861             :   inline Object CurrentKey();
     862             : 
     863             :  private:
     864             :   // Transitions the iterator to the non obsolete backing store. This is a NOP
     865             :   // if the [table] is not obsolete.
     866             :   void Transition();
     867             : 
     868             :   OBJECT_CONSTRUCTORS(OrderedHashTableIterator, JSCollectionIterator);
     869             : };
     870             : 
     871             : }  // namespace internal
     872             : }  // namespace v8
     873             : 
     874             : #include "src/objects/object-macros-undef.h"
     875             : 
     876             : #endif  // V8_OBJECTS_ORDERED_HASH_TABLE_H_

Generated by: LCOV version 1.10