[dict] Store hash in prefix slot

Sets the hash default when dictionary is created.
Migrates the hash correctly when the dictionary grows.

Bug: v8:6443, v8:7569
Change-Id: I9195b557796b9bd3d040bd6f4f77d1f9ead4fc7d
Reviewed-on: https://chromium-review.googlesource.com/c/1337744
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58181}
This commit is contained in:
Sathya Gunasekaran 2018-12-11 12:06:23 -08:00 committed by Commit Bot
parent 98bbb636b1
commit bef0d03c73
5 changed files with 186 additions and 24 deletions

View File

@ -564,8 +564,11 @@ Handle<SmallOrderedHashMap> Factory::NewSmallOrderedHashMap(
Handle<SmallOrderedNameDictionary> Factory::NewSmallOrderedNameDictionary(
int capacity, PretenureFlag pretenure) {
return AllocateSmallOrderedHashTable<SmallOrderedNameDictionary>(
small_ordered_name_dictionary_map(), capacity, pretenure);
Handle<SmallOrderedNameDictionary> dict =
AllocateSmallOrderedHashTable<SmallOrderedNameDictionary>(
small_ordered_name_dictionary_map(), capacity, pretenure);
dict->SetHash(PropertyArray::kNoHashSentinel);
return dict;
}
Handle<OrderedHashSet> Factory::NewOrderedHashSet() {

View File

@ -170,6 +170,29 @@ Object* OrderedHashTableIterator<Derived, TableType>::CurrentKey() {
return key;
}
inline void SmallOrderedNameDictionary::SetHash(int hash) {
DCHECK(PropertyArray::HashField::is_valid(hash));
WRITE_INT_FIELD(this, PrefixOffset(), hash);
}
inline int SmallOrderedNameDictionary::Hash() {
int hash = READ_INT_FIELD(this, PrefixOffset());
DCHECK(PropertyArray::HashField::is_valid(hash));
return hash;
}
inline void OrderedNameDictionary::SetHash(int hash) {
DCHECK(PropertyArray::HashField::is_valid(hash));
this->set(PrefixIndex(), Smi::FromInt(hash));
}
inline int OrderedNameDictionary::Hash() {
Object* hash_obj = this->get(PrefixIndex());
int hash = Smi::ToInt(hash_obj);
DCHECK(PropertyArray::HashField::is_valid(hash));
return hash;
}
} // namespace internal
} // namespace v8

View File

@ -50,8 +50,8 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::EnsureGrowable(
// Don't need to grow if we can simply clear out deleted entries instead.
// Note that we can't compact in place, though, so we always allocate
// a new table.
return Rehash(isolate, table,
(nod < (capacity >> 1)) ? capacity << 1 : capacity);
return Derived::Rehash(isolate, table,
(nod < (capacity >> 1)) ? capacity << 1 : capacity);
}
template <class Derived, int entrysize>
@ -62,7 +62,7 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Shrink(
int nof = table->NumberOfElements();
int capacity = table->Capacity();
if (nof >= (capacity >> 2)) return table;
return Rehash(isolate, table, capacity / 2);
return Derived::Rehash(isolate, table, capacity / 2);
}
template <class Derived, int entrysize>
@ -187,7 +187,7 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
Isolate* isolate, Handle<Derived> table, int new_capacity) {
DCHECK(!table->IsObsolete());
Handle<Derived> new_table = Allocate(
Handle<Derived> new_table = Derived::Allocate(
isolate, new_capacity, Heap::InNewSpace(*table) ? NOT_TENURED : TENURED);
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
@ -225,6 +225,29 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
return new_table;
}
Handle<OrderedHashSet> OrderedHashSet::Rehash(Isolate* isolate,
Handle<OrderedHashSet> table,
int new_capacity) {
return OrderedHashTable<OrderedHashSet, 1>::Rehash(isolate, table,
new_capacity);
}
Handle<OrderedHashMap> OrderedHashMap::Rehash(Isolate* isolate,
Handle<OrderedHashMap> table,
int new_capacity) {
return OrderedHashTable<OrderedHashMap, 2>::Rehash(isolate, table,
new_capacity);
}
Handle<OrderedNameDictionary> OrderedNameDictionary::Rehash(
Isolate* isolate, Handle<OrderedNameDictionary> table, int new_capacity) {
Handle<OrderedNameDictionary> new_table =
OrderedHashTable<OrderedNameDictionary, 3>::Rehash(isolate, table,
new_capacity);
new_table->SetHash(table->Hash());
return new_table;
}
template <class Derived, int entrysize>
bool OrderedHashTable<Derived, entrysize>::Delete(Isolate* isolate,
Derived table, Object* key) {
@ -361,9 +384,26 @@ int OrderedHashTable<OrderedNameDictionary, 3>::FindEntry(Isolate* isolate,
return kNotFound;
}
Handle<OrderedHashSet> OrderedHashSet::Allocate(Isolate* isolate, int capacity,
PretenureFlag pretenure) {
return OrderedHashTable<OrderedHashSet, 1>::Allocate(isolate, capacity,
pretenure);
}
template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure);
Handle<OrderedHashMap> OrderedHashMap::Allocate(Isolate* isolate, int capacity,
PretenureFlag pretenure) {
return OrderedHashTable<OrderedHashMap, 2>::Allocate(isolate, capacity,
pretenure);
}
Handle<OrderedNameDictionary> OrderedNameDictionary::Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure) {
Handle<OrderedNameDictionary> table =
OrderedHashTable<OrderedNameDictionary, 3>::Allocate(isolate, capacity,
pretenure);
table->SetHash(PropertyArray::kNoHashSentinel);
return table;
}
template Handle<OrderedHashSet>
OrderedHashTable<OrderedHashSet, 1>::EnsureGrowable(
@ -386,9 +426,6 @@ template bool OrderedHashTable<OrderedHashSet, 1>::Delete(Isolate* isolate,
template int OrderedHashTable<OrderedHashSet, 1>::FindEntry(Isolate* isolate,
Object* key);
template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure);
template Handle<OrderedHashMap>
OrderedHashTable<OrderedHashMap, 2>::EnsureGrowable(
Isolate* isolate, Handle<OrderedHashMap> table);
@ -410,10 +447,6 @@ template bool OrderedHashTable<OrderedHashMap, 2>::Delete(Isolate* isolate,
template int OrderedHashTable<OrderedHashMap, 2>::FindEntry(Isolate* isolate,
Object* key);
template Handle<OrderedNameDictionary>
OrderedHashTable<OrderedNameDictionary, 3>::Allocate(Isolate* isolate,
int capacity,
PretenureFlag pretenure);
template bool OrderedHashTable<OrderedNameDictionary, 3>::HasKey(
Isolate* isolate, OrderedNameDictionary table, Object* key);
@ -662,6 +695,28 @@ Handle<Derived> SmallOrderedHashTable<Derived>::Rehash(Isolate* isolate,
return new_table;
}
Handle<SmallOrderedHashSet> SmallOrderedHashSet::Rehash(
Isolate* isolate, Handle<SmallOrderedHashSet> table, int new_capacity) {
return SmallOrderedHashTable<SmallOrderedHashSet>::Rehash(isolate, table,
new_capacity);
}
Handle<SmallOrderedHashMap> SmallOrderedHashMap::Rehash(
Isolate* isolate, Handle<SmallOrderedHashMap> table, int new_capacity) {
return SmallOrderedHashTable<SmallOrderedHashMap>::Rehash(isolate, table,
new_capacity);
}
Handle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::Rehash(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
int new_capacity) {
Handle<SmallOrderedNameDictionary> new_table =
SmallOrderedHashTable<SmallOrderedNameDictionary>::Rehash(isolate, table,
new_capacity);
new_table->SetHash(table->Hash());
return new_table;
}
template <class Derived>
MaybeHandle<Derived> SmallOrderedHashTable<Derived>::Grow(
Isolate* isolate, Handle<Derived> table) {
@ -686,7 +741,7 @@ MaybeHandle<Derived> SmallOrderedHashTable<Derived>::Grow(
}
}
return Rehash(isolate, table, new_capacity);
return Derived::Rehash(isolate, table, new_capacity);
}
template <class Derived>

View File

@ -60,10 +60,6 @@ namespace internal {
template <class Derived, int entrysize>
class OrderedHashTable : public FixedArray {
public:
// Returns an OrderedHashTable with a capacity of at least |capacity|.
static Handle<Derived> Allocate(Isolate* isolate, int capacity,
PretenureFlag pretenure = NOT_TENURED);
// Returns an OrderedHashTable (possibly |table|) with enough space
// to add at least one new element.
static Handle<Derived> EnsureGrowable(Isolate* isolate,
@ -138,6 +134,7 @@ class OrderedHashTable : public FixedArray {
return Smi::ToInt(get(RemovedHolesIndex() + index));
}
// The extra +1 is for linking the bucket chains together.
static const int kEntrySize = entrysize + 1;
static const int kChainOffset = entrysize;
@ -197,6 +194,9 @@ class OrderedHashTable : public FixedArray {
}
protected:
// Returns an OrderedHashTable with a capacity of at least |capacity|.
static Handle<Derived> Allocate(Isolate* isolate, int capacity,
PretenureFlag pretenure = NOT_TENURED);
static Handle<Derived> Rehash(Isolate* isolate, Handle<Derived> table,
int new_capacity);
@ -234,6 +234,11 @@ class OrderedHashSet : public OrderedHashTable<OrderedHashSet, 1> {
static Handle<FixedArray> ConvertToKeysArray(Isolate* isolate,
Handle<OrderedHashSet> table,
GetKeysConversion convert);
static Handle<OrderedHashSet> Rehash(Isolate* isolate,
Handle<OrderedHashSet> table,
int new_capacity);
static Handle<OrderedHashSet> Allocate(Isolate* isolate, int capacity,
PretenureFlag pretenure = NOT_TENURED);
static HeapObject* GetEmpty(ReadOnlyRoots ro_roots);
static inline RootIndex GetMapRootIndex();
static inline bool Is(Handle<HeapObject> table);
@ -251,6 +256,12 @@ class OrderedHashMap : public OrderedHashTable<OrderedHashMap, 2> {
static Handle<OrderedHashMap> Add(Isolate* isolate,
Handle<OrderedHashMap> table,
Handle<Object> key, Handle<Object> value);
static Handle<OrderedHashMap> Allocate(Isolate* isolate, int capacity,
PretenureFlag pretenure = NOT_TENURED);
static Handle<OrderedHashMap> Rehash(Isolate* isolate,
Handle<OrderedHashMap> table,
int new_capacity);
Object* ValueAt(int entry);
static Object* GetHash(Isolate* isolate, Object* key);
@ -339,9 +350,6 @@ class SmallOrderedHashTable : public HeapObjectPtr {
// we've already reached MaxCapacity.
static MaybeHandle<Derived> Grow(Isolate* isolate, Handle<Derived> table);
static Handle<Derived> Rehash(Isolate* isolate, Handle<Derived> table,
int new_capacity);
int FindEntry(Isolate* isolate, Object* key);
// Iterates only fields in the DataTable.
@ -414,6 +422,9 @@ class SmallOrderedHashTable : public HeapObjectPtr {
static const int kGrowthHack = 256;
protected:
static Handle<Derived> Rehash(Isolate* isolate, Handle<Derived> table,
int new_capacity);
void SetDataEntry(int entry, int relative_index, Object* value);
// TODO(gsathya): Calculate all the various possible values for this
@ -573,7 +584,9 @@ class SmallOrderedHashSet : public SmallOrderedHashTable<SmallOrderedHashSet> {
Handle<Object> key);
static inline bool Is(Handle<HeapObject> table);
static inline RootIndex GetMapRootIndex();
static Handle<SmallOrderedHashSet> Rehash(Isolate* isolate,
Handle<SmallOrderedHashSet> table,
int new_capacity);
OBJECT_CONSTRUCTORS(SmallOrderedHashSet,
SmallOrderedHashTable<SmallOrderedHashSet>)
};
@ -599,6 +612,10 @@ class SmallOrderedHashMap : public SmallOrderedHashTable<SmallOrderedHashMap> {
static inline bool Is(Handle<HeapObject> table);
static inline RootIndex GetMapRootIndex();
static Handle<SmallOrderedHashMap> Rehash(Isolate* isolate,
Handle<SmallOrderedHashMap> table,
int new_capacity);
OBJECT_CONSTRUCTORS(SmallOrderedHashMap,
SmallOrderedHashTable<SmallOrderedHashMap>)
};
@ -651,6 +668,12 @@ class OrderedNameDictionary
Handle<Object> value,
PropertyDetails details);
static Handle<OrderedNameDictionary> Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure = NOT_TENURED);
static Handle<OrderedNameDictionary> Rehash(
Isolate* isolate, Handle<OrderedNameDictionary> table, int new_capacity);
// Returns the value for entry.
inline Object* ValueAt(int entry);
@ -663,6 +686,9 @@ class OrderedNameDictionary
// Set the details for entry.
inline void DetailsAtPut(int entry, PropertyDetails value);
inline void SetHash(int hash);
inline int Hash();
static HeapObject* GetEmpty(ReadOnlyRoots ro_roots);
static inline RootIndex GetMapRootIndex();
@ -684,6 +710,10 @@ class SmallOrderedNameDictionary
// Returns the value for entry.
inline Object* ValueAt(int entry);
static Handle<SmallOrderedNameDictionary> Rehash(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
int new_capacity);
// Set the value for entry.
inline void ValueAtPut(int entry, Object* value);
@ -693,6 +723,9 @@ class SmallOrderedNameDictionary
// Set the details for entry.
inline void DetailsAtPut(int entry, PropertyDetails value);
inline void SetHash(int hash);
inline int Hash();
static const int kKeyIndex = 0;
static const int kValueIndex = 1;
static const int kPropertyDetailsIndex = 2;

View File

@ -1682,6 +1682,54 @@ TEST(SmallOrderedNameDictionaryDetailsAtAndDetailsAtPut) {
CHECK_EQ(other.AsSmi(), found.AsSmi());
}
TEST(SmallOrderedNameDictionarySetAndMigrateHash) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<SmallOrderedNameDictionary> dict =
factory->NewSmallOrderedNameDictionary();
Handle<String> value = isolate->factory()->InternalizeUtf8String("bar");
PropertyDetails details = PropertyDetails::Empty();
CHECK_EQ(PropertyArray::kNoHashSentinel, dict->Hash());
dict->SetHash(100);
CHECK_EQ(100, dict->Hash());
char buf[10];
for (int i = 0; i < SmallOrderedNameDictionary::kMaxCapacity; i++) {
CHECK_LT(0, snprintf(buf, sizeof(buf), "foo%d", i));
Handle<String> key = isolate->factory()->InternalizeUtf8String(buf);
dict = SmallOrderedNameDictionary::Add(isolate, dict, key, value, details)
.ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(100, dict->Hash());
}
}
TEST(OrderedNameDictionarySetAndMigrateHash) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<OrderedNameDictionary> dict = factory->NewOrderedNameDictionary();
Handle<String> value = isolate->factory()->InternalizeUtf8String("bar");
PropertyDetails details = PropertyDetails::Empty();
CHECK_EQ(PropertyArray::kNoHashSentinel, dict->Hash());
dict->SetHash(100);
CHECK_EQ(100, dict->Hash());
char buf[10];
for (int i = 0; i <= 1024; i++) {
CHECK_LT(0, snprintf(buf, sizeof(buf), "foo%d", i));
Handle<String> key = isolate->factory()->InternalizeUtf8String(buf);
dict = OrderedNameDictionary::Add(isolate, dict, key, value, details);
Verify(isolate, dict);
CHECK_EQ(100, dict->Hash());
}
}
} // namespace test_orderedhashtable
} // namespace internal
} // namespace v8