Commit da02f095 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[hash-table] Introduce OrderedHashTableHandler

OrderedHashTableHandler (to be renamed to OrderedHashTable) is the
interface that abstracts away the two different ordered hash tables.

All operations on the two ordered hash tables must be performed
through this new interface so that we can seamlessly migrate from one
table to another behind the scenes.

Bug: v8:6443, v8:7569
Change-Id: Ifc0a38974605b63e0a2a36b4aafb8dc68a081f4a
Reviewed-on: https://chromium-review.googlesource.com/1059865
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53622}
parent 2530a044
...@@ -24,6 +24,21 @@ inline Object* OrderedHashMap::ValueAt(int entry) { ...@@ -24,6 +24,21 @@ inline Object* OrderedHashMap::ValueAt(int entry) {
return get(EntryToIndex(entry) + kValueOffset); return get(EntryToIndex(entry) + kValueOffset);
} }
inline bool OrderedHashSet::Is(Handle<HeapObject> table) {
return table->IsOrderedHashSet();
}
inline bool OrderedHashMap::Is(Handle<HeapObject> table) {
return table->IsOrderedHashMap();
}
inline bool SmallOrderedHashSet::Is(Handle<HeapObject> table) {
return table->IsSmallOrderedHashSet();
}
inline bool SmallOrderedHashMap::Is(Handle<HeapObject> table) {
return table->IsSmallOrderedHashMap();
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -362,13 +362,17 @@ void SmallOrderedHashTable<Derived>::Initialize(Isolate* isolate, ...@@ -362,13 +362,17 @@ void SmallOrderedHashTable<Derived>::Initialize(Isolate* isolate,
#endif // DEBUG #endif // DEBUG
} }
Handle<SmallOrderedHashSet> SmallOrderedHashSet::Add( MaybeHandle<SmallOrderedHashSet> SmallOrderedHashSet::Add(
Handle<SmallOrderedHashSet> table, Handle<Object> key) { Handle<SmallOrderedHashSet> table, Handle<Object> key) {
Isolate* isolate = table->GetIsolate(); Isolate* isolate = table->GetIsolate();
if (table->HasKey(isolate, key)) return table; if (table->HasKey(isolate, key)) return table;
if (table->UsedCapacity() >= table->Capacity()) { if (table->UsedCapacity() >= table->Capacity()) {
table = SmallOrderedHashSet::Grow(table); MaybeHandle<SmallOrderedHashSet> new_table =
SmallOrderedHashSet::Grow(table);
if (!new_table.ToHandle(&table)) {
return MaybeHandle<SmallOrderedHashSet>();
}
} }
int hash = key->GetOrCreateHash(table->GetIsolate())->value(); int hash = key->GetOrCreateHash(table->GetIsolate())->value();
...@@ -391,14 +395,18 @@ Handle<SmallOrderedHashSet> SmallOrderedHashSet::Add( ...@@ -391,14 +395,18 @@ Handle<SmallOrderedHashSet> SmallOrderedHashSet::Add(
return table; return table;
} }
Handle<SmallOrderedHashMap> SmallOrderedHashMap::Add( MaybeHandle<SmallOrderedHashMap> SmallOrderedHashMap::Add(
Handle<SmallOrderedHashMap> table, Handle<Object> key, Handle<SmallOrderedHashMap> table, Handle<Object> key,
Handle<Object> value) { Handle<Object> value) {
Isolate* isolate = table->GetIsolate(); Isolate* isolate = table->GetIsolate();
if (table->HasKey(isolate, key)) return table; if (table->HasKey(isolate, key)) return table;
if (table->UsedCapacity() >= table->Capacity()) { if (table->UsedCapacity() >= table->Capacity()) {
table = SmallOrderedHashMap::Grow(table); MaybeHandle<SmallOrderedHashMap> new_table =
SmallOrderedHashMap::Grow(table);
if (!new_table.ToHandle(&table)) {
return MaybeHandle<SmallOrderedHashMap>();
}
} }
int hash = key->GetOrCreateHash(table->GetIsolate())->value(); int hash = key->GetOrCreateHash(table->GetIsolate())->value();
...@@ -490,7 +498,8 @@ Handle<Derived> SmallOrderedHashTable<Derived>::Rehash(Handle<Derived> table, ...@@ -490,7 +498,8 @@ Handle<Derived> SmallOrderedHashTable<Derived>::Rehash(Handle<Derived> table,
} }
template <class Derived> template <class Derived>
Handle<Derived> SmallOrderedHashTable<Derived>::Grow(Handle<Derived> table) { MaybeHandle<Derived> SmallOrderedHashTable<Derived>::Grow(
Handle<Derived> table) {
int capacity = table->Capacity(); int capacity = table->Capacity();
int new_capacity = capacity; int new_capacity = capacity;
...@@ -506,7 +515,10 @@ Handle<Derived> SmallOrderedHashTable<Derived>::Grow(Handle<Derived> table) { ...@@ -506,7 +515,10 @@ Handle<Derived> SmallOrderedHashTable<Derived>::Grow(Handle<Derived> table) {
new_capacity = kMaxCapacity; new_capacity = kMaxCapacity;
} }
// TODO(gsathya): Transition to OrderedHashTable for size > kMaxCapacity. // We need to migrate to a bigger hash table.
if (new_capacity > kMaxCapacity) {
return MaybeHandle<Derived>();
}
} }
return Rehash(table, new_capacity); return Rehash(table, new_capacity);
...@@ -517,7 +529,7 @@ template bool SmallOrderedHashTable<SmallOrderedHashSet>::HasKey( ...@@ -517,7 +529,7 @@ template bool SmallOrderedHashTable<SmallOrderedHashSet>::HasKey(
template Handle<SmallOrderedHashSet> template Handle<SmallOrderedHashSet>
SmallOrderedHashTable<SmallOrderedHashSet>::Rehash( SmallOrderedHashTable<SmallOrderedHashSet>::Rehash(
Handle<SmallOrderedHashSet> table, int new_capacity); Handle<SmallOrderedHashSet> table, int new_capacity);
template Handle<SmallOrderedHashSet> SmallOrderedHashTable< template MaybeHandle<SmallOrderedHashSet> SmallOrderedHashTable<
SmallOrderedHashSet>::Grow(Handle<SmallOrderedHashSet> table); SmallOrderedHashSet>::Grow(Handle<SmallOrderedHashSet> table);
template void SmallOrderedHashTable<SmallOrderedHashSet>::Initialize( template void SmallOrderedHashTable<SmallOrderedHashSet>::Initialize(
Isolate* isolate, int capacity); Isolate* isolate, int capacity);
...@@ -527,7 +539,7 @@ template bool SmallOrderedHashTable<SmallOrderedHashMap>::HasKey( ...@@ -527,7 +539,7 @@ template bool SmallOrderedHashTable<SmallOrderedHashMap>::HasKey(
template Handle<SmallOrderedHashMap> template Handle<SmallOrderedHashMap>
SmallOrderedHashTable<SmallOrderedHashMap>::Rehash( SmallOrderedHashTable<SmallOrderedHashMap>::Rehash(
Handle<SmallOrderedHashMap> table, int new_capacity); Handle<SmallOrderedHashMap> table, int new_capacity);
template Handle<SmallOrderedHashMap> SmallOrderedHashTable< template MaybeHandle<SmallOrderedHashMap> SmallOrderedHashTable<
SmallOrderedHashMap>::Grow(Handle<SmallOrderedHashMap> table); SmallOrderedHashMap>::Grow(Handle<SmallOrderedHashMap> table);
template void SmallOrderedHashTable<SmallOrderedHashMap>::Initialize( template void SmallOrderedHashTable<SmallOrderedHashMap>::Initialize(
Isolate* isolate, int capacity); Isolate* isolate, int capacity);
...@@ -537,6 +549,133 @@ template bool SmallOrderedHashTable<SmallOrderedHashMap>::Delete( ...@@ -537,6 +549,133 @@ template bool SmallOrderedHashTable<SmallOrderedHashMap>::Delete(
template bool SmallOrderedHashTable<SmallOrderedHashSet>::Delete( template bool SmallOrderedHashTable<SmallOrderedHashSet>::Delete(
Isolate* isolate, SmallOrderedHashSet* table, Object* key); Isolate* isolate, SmallOrderedHashSet* table, Object* key);
template <class SmallTable, class LargeTable>
Handle<HeapObject> OrderedHashTableHandler<SmallTable, LargeTable>::Allocate(
Isolate* isolate, int capacity) {
if (capacity < SmallTable::kMaxCapacity) {
return SmallTable::Allocate(isolate, capacity);
}
return LargeTable::Allocate(isolate, capacity);
}
template Handle<HeapObject>
OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet>::Allocate(
Isolate* isolate, int capacity);
template Handle<HeapObject>
OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap>::Allocate(
Isolate* isolate, int capacity);
template <class SmallTable, class LargeTable>
bool OrderedHashTableHandler<SmallTable, LargeTable>::Delete(
Handle<HeapObject> table, Handle<Object> key) {
if (SmallTable::Is(table)) {
return SmallTable::Delete(Handle<SmallTable>::cast(table), key);
}
DCHECK(LargeTable::Is(table));
// Note: Once we migrate to the a big hash table, we never migrate
// down to a smaller hash table.
return LargeTable::Delete(Handle<LargeTable>::cast(table), key);
}
template <class SmallTable, class LargeTable>
bool OrderedHashTableHandler<SmallTable, LargeTable>::HasKey(
Isolate* isolate, Handle<HeapObject> table, Handle<Object> key) {
if (SmallTable::Is(table)) {
return Handle<SmallTable>::cast(table)->HasKey(isolate, key);
}
DCHECK(LargeTable::Is(table));
return LargeTable::HasKey(isolate, LargeTable::cast(*table), *key);
}
template bool
OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet>::HasKey(
Isolate* isolate, Handle<HeapObject> table, Handle<Object> key);
template bool
OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap>::HasKey(
Isolate* isolate, Handle<HeapObject> table, Handle<Object> key);
Handle<OrderedHashMap> OrderedHashMapHandler::AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedHashMap> table) {
Handle<OrderedHashMap> new_table =
OrderedHashMap::Allocate(isolate, OrderedHashTableMinSize);
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
// TODO(gsathya): Optimize the lookup to not re calc offsets. Also,
// unhandlify this code as we preallocate the new backing store with
// the proper capacity.
for (int entry = 0; entry < (nof + nod); ++entry) {
Handle<Object> key = handle(table->KeyAt(entry), isolate);
if (key->IsTheHole(isolate)) continue;
Handle<Object> value = handle(
table->GetDataEntry(entry, SmallOrderedHashMap::kValueIndex), isolate);
new_table = OrderedHashMap::Add(new_table, key, value);
}
return new_table;
}
Handle<OrderedHashSet> OrderedHashSetHandler::AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedHashSet> table) {
Handle<OrderedHashSet> new_table =
OrderedHashSet::Allocate(isolate, OrderedHashTableMinSize);
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
// TODO(gsathya): Optimize the lookup to not re calc offsets. Also,
// unhandlify this code as we preallocate the new backing store with
// the proper capacity.
for (int entry = 0; entry < (nof + nod); ++entry) {
Handle<Object> key = handle(table->KeyAt(entry), isolate);
if (key->IsTheHole(isolate)) continue;
new_table = OrderedHashSet::Add(new_table, key);
}
return new_table;
}
Handle<HeapObject> OrderedHashMapHandler::Add(Isolate* isolate,
Handle<HeapObject> table,
Handle<Object> key,
Handle<Object> value) {
if (table->IsSmallOrderedHashMap()) {
Handle<SmallOrderedHashMap> small_map =
Handle<SmallOrderedHashMap>::cast(table);
MaybeHandle<SmallOrderedHashMap> new_map =
SmallOrderedHashMap::Add(small_map, key, value);
if (!new_map.is_null()) return new_map.ToHandleChecked();
// We couldn't add to the small table, let's migrate to the
// big table.
table = OrderedHashMapHandler::AdjustRepresentation(isolate, small_map);
}
DCHECK(table->IsOrderedHashMap());
return OrderedHashMap::Add(Handle<OrderedHashMap>::cast(table), key, value);
}
Handle<HeapObject> OrderedHashSetHandler::Add(Isolate* isolate,
Handle<HeapObject> table,
Handle<Object> key) {
if (table->IsSmallOrderedHashSet()) {
Handle<SmallOrderedHashSet> small_set =
Handle<SmallOrderedHashSet>::cast(table);
MaybeHandle<SmallOrderedHashSet> new_set =
SmallOrderedHashSet::Add(small_set, key);
if (!new_set.is_null()) return new_set.ToHandleChecked();
// We couldn't add to the small table, let's migrate to the
// big table.
table = OrderedHashSetHandler::AdjustRepresentation(isolate, small_set);
}
DCHECK(table->IsOrderedHashSet());
return OrderedHashSet::Add(Handle<OrderedHashSet>::cast(table), key);
}
template <class Derived, class TableType> template <class Derived, class TableType>
void OrderedHashTableIterator<Derived, TableType>::Transition() { void OrderedHashTableIterator<Derived, TableType>::Transition() {
DisallowHeapAllocation no_allocation; DisallowHeapAllocation no_allocation;
......
...@@ -228,6 +228,7 @@ class OrderedHashSet : public OrderedHashTable<OrderedHashSet, 1> { ...@@ -228,6 +228,7 @@ class OrderedHashSet : public OrderedHashTable<OrderedHashSet, 1> {
GetKeysConversion convert); GetKeysConversion convert);
static HeapObject* GetEmpty(Isolate* isolate); static HeapObject* GetEmpty(Isolate* isolate);
static inline int GetMapRootIndex(); static inline int GetMapRootIndex();
static inline bool Is(Handle<HeapObject> table);
}; };
class OrderedHashMap : public OrderedHashTable<OrderedHashMap, 2> { class OrderedHashMap : public OrderedHashTable<OrderedHashMap, 2> {
...@@ -244,6 +245,7 @@ class OrderedHashMap : public OrderedHashTable<OrderedHashMap, 2> { ...@@ -244,6 +245,7 @@ class OrderedHashMap : public OrderedHashTable<OrderedHashMap, 2> {
static HeapObject* GetEmpty(Isolate* isolate); static HeapObject* GetEmpty(Isolate* isolate);
static inline int GetMapRootIndex(); static inline int GetMapRootIndex();
static inline bool Is(Handle<HeapObject> table);
static const int kValueOffset = 1; static const int kValueOffset = 1;
}; };
...@@ -309,8 +311,9 @@ class SmallOrderedHashTable : public HeapObject { ...@@ -309,8 +311,9 @@ class SmallOrderedHashTable : public HeapObject {
static bool Delete(Isolate* isolate, Derived* table, Object* key); static bool Delete(Isolate* isolate, Derived* table, Object* key);
// Returns an SmallOrderedHashTable (possibly |table|) with enough // Returns an SmallOrderedHashTable (possibly |table|) with enough
// space to add at least one new element. // space to add at least one new element. Returns empty handle if
static Handle<Derived> Grow(Handle<Derived> table); // we've already reached MaxCapacity.
static MaybeHandle<Derived> Grow(Handle<Derived> table);
static Handle<Derived> Rehash(Handle<Derived> table, int new_capacity); static Handle<Derived> Rehash(Handle<Derived> table, int new_capacity);
...@@ -379,6 +382,13 @@ class SmallOrderedHashTable : public HeapObject { ...@@ -379,6 +382,13 @@ class SmallOrderedHashTable : public HeapObject {
// should be stored as another field of this object. // should be stored as another field of this object.
static const int kLoadFactor = 2; static const int kLoadFactor = 2;
// Our growth strategy involves doubling the capacity until we reach
// kMaxCapacity, but since the kMaxCapacity is always less than 256,
// we will never fully utilize this table. We special case for 256,
// by changing the new capacity to be kMaxCapacity in
// SmallOrderedHashTable::Grow.
static const int kGrowthHack = 256;
protected: protected:
void SetDataEntry(int entry, int relative_index, Object* value); void SetDataEntry(int entry, int relative_index, Object* value);
...@@ -490,13 +500,6 @@ class SmallOrderedHashTable : public HeapObject { ...@@ -490,13 +500,6 @@ class SmallOrderedHashTable : public HeapObject {
return capacity * Derived::kEntrySize * kPointerSize; return capacity * Derived::kEntrySize * kPointerSize;
} }
// Our growth strategy involves doubling the capacity until we reach
// kMaxCapacity, but since the kMaxCapacity is always less than 256,
// we will never fully utilize this table. We special case for 256,
// by changing the new capacity to be kMaxCapacity in
// SmallOrderedHashTable::Grow.
static const int kGrowthHack = 256;
// This is used for accessing the non |DataTable| part of the // This is used for accessing the non |DataTable| part of the
// structure. // structure.
byte getByte(Offset offset, ByteIndex index) const { byte getByte(Offset offset, ByteIndex index) const {
...@@ -523,6 +526,10 @@ class SmallOrderedHashTable : public HeapObject { ...@@ -523,6 +526,10 @@ class SmallOrderedHashTable : public HeapObject {
return used; return used;
} }
private:
friend class OrderedHashMapHandler;
friend class OrderedHashSetHandler;
}; };
class SmallOrderedHashSet : public SmallOrderedHashTable<SmallOrderedHashSet> { class SmallOrderedHashSet : public SmallOrderedHashTable<SmallOrderedHashSet> {
...@@ -537,8 +544,9 @@ class SmallOrderedHashSet : public SmallOrderedHashTable<SmallOrderedHashSet> { ...@@ -537,8 +544,9 @@ class SmallOrderedHashSet : public SmallOrderedHashTable<SmallOrderedHashSet> {
// Adds |value| to |table|, if the capacity isn't enough, a new // Adds |value| to |table|, if the capacity isn't enough, a new
// table is created. The original |table| is returned if there is // table is created. The original |table| is returned if there is
// capacity to store |value| otherwise the new table is returned. // capacity to store |value| otherwise the new table is returned.
static Handle<SmallOrderedHashSet> Add(Handle<SmallOrderedHashSet> table, static MaybeHandle<SmallOrderedHashSet> Add(Handle<SmallOrderedHashSet> table,
Handle<Object> key); Handle<Object> key);
static inline bool Is(Handle<HeapObject> table);
}; };
class SmallOrderedHashMap : public SmallOrderedHashTable<SmallOrderedHashMap> { class SmallOrderedHashMap : public SmallOrderedHashTable<SmallOrderedHashMap> {
...@@ -554,9 +562,47 @@ class SmallOrderedHashMap : public SmallOrderedHashTable<SmallOrderedHashMap> { ...@@ -554,9 +562,47 @@ class SmallOrderedHashMap : public SmallOrderedHashTable<SmallOrderedHashMap> {
// Adds |value| to |table|, if the capacity isn't enough, a new // Adds |value| to |table|, if the capacity isn't enough, a new
// table is created. The original |table| is returned if there is // table is created. The original |table| is returned if there is
// capacity to store |value| otherwise the new table is returned. // capacity to store |value| otherwise the new table is returned.
static Handle<SmallOrderedHashMap> Add(Handle<SmallOrderedHashMap> table, static MaybeHandle<SmallOrderedHashMap> Add(Handle<SmallOrderedHashMap> table,
Handle<Object> key, Handle<Object> key,
Handle<Object> value); Handle<Object> value);
static inline bool Is(Handle<HeapObject> table);
};
// TODO(gsathya): Rename this to OrderedHashTable, after we rename
// OrderedHashTable to LargeOrderedHashTable. Also set up a
// OrderedHashSetBase class as a base class for the two tables and use
// that instead of a HeapObject here.
template <class SmallTable, class LargeTable>
class OrderedHashTableHandler {
public:
typedef int Entry;
static Handle<HeapObject> Allocate(Isolate* isolate, int capacity);
static bool Delete(Handle<HeapObject> table, Handle<Object> key);
static bool HasKey(Isolate* isolate, Handle<HeapObject> table,
Handle<Object> key);
// TODO(gsathya): Move this to OrderedHashTable
static const int OrderedHashTableMinSize =
SmallOrderedHashTable<SmallTable>::kGrowthHack << 1;
};
class OrderedHashMapHandler
: public OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap> {
public:
static Handle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
Handle<Object> key, Handle<Object> value);
static Handle<OrderedHashMap> AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedHashMap> table);
};
class OrderedHashSetHandler
: public OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet> {
public:
static Handle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
Handle<Object> key);
static Handle<OrderedHashSet> AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedHashSet> table);
}; };
class JSCollectionIterator : public JSObject { class JSCollectionIterator : public JSObject {
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment