[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:
parent
98bbb636b1
commit
bef0d03c73
@ -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() {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user