diff --git a/src/objects/objects.cc b/src/objects/objects.cc index d9cb7486be..a42715420a 100644 --- a/src/objects/objects.cc +++ b/src/objects/objects.cc @@ -1960,6 +1960,10 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT case NAME_DICTIONARY_TYPE: os << ""; break; + case SWISS_NAME_DICTIONARY_TYPE: + os << ""; + break; case GLOBAL_DICTIONARY_TYPE: os << ""; break; @@ -2351,6 +2355,7 @@ bool HeapObject::NeedsRehashing(InstanceType instance_type) const { case SMALL_ORDERED_HASH_MAP_TYPE: case SMALL_ORDERED_HASH_SET_TYPE: case SMALL_ORDERED_NAME_DICTIONARY_TYPE: + case SWISS_NAME_DICTIONARY_TYPE: case JS_MAP_TYPE: case JS_SET_TYPE: return true; @@ -2374,6 +2379,7 @@ bool HeapObject::CanBeRehashed() const { case GLOBAL_DICTIONARY_TYPE: case NUMBER_DICTIONARY_TYPE: case SIMPLE_NUMBER_DICTIONARY_TYPE: + case SWISS_NAME_DICTIONARY_TYPE: return true; case DESCRIPTOR_ARRAY_TYPE: case STRONG_DESCRIPTOR_ARRAY_TYPE: @@ -2399,6 +2405,9 @@ void HeapObject::RehashBasedOnMap(Isolate* isolate) { case NAME_DICTIONARY_TYPE: NameDictionary::cast(*this).Rehash(isolate); break; + case SWISS_NAME_DICTIONARY_TYPE: + SwissNameDictionary::cast(*this).Rehash(isolate); + break; case GLOBAL_DICTIONARY_TYPE: GlobalDictionary::cast(*this).Rehash(isolate); break; diff --git a/src/objects/swiss-name-dictionary.cc b/src/objects/swiss-name-dictionary.cc index b503feea8f..4db76d566d 100644 --- a/src/objects/swiss-name-dictionary.cc +++ b/src/objects/swiss-name-dictionary.cc @@ -94,6 +94,60 @@ Handle SwissNameDictionary::Shrink( return Rehash(isolate, table, new_capacity); } +// TODO(v8::11388) Copying all data into a std::vector and then re-adding into +// the table doesn't seem like a good algorithm. Abseil's Swiss Tables come with +// a clever algorithm for re-hashing in place: It first changes the control +// table, effectively changing the roles of full, empty and deleted buckets. It +// then moves each entry to its new bucket by swapping entries (see +// drop_deletes_without_resize in Abseil's raw_hash_set.h). This algorithm could +// generally adapted to work on our insertion order preserving implementation, +// too. However, it would require a mapping from hash table buckets back to +// enumeration indices. This could either be be created in this function +// (requiring a vector with Capacity() entries and a separate pass over the +// enumeration table) or by creating this backwards mapping ahead of time and +// storing it somewhere in the main table or the meta table, for those +// SwissNameDictionaries that we know will be in-place rehashed, most notably +// those stored in the snapshot. +void SwissNameDictionary::Rehash(Isolate* isolate) { + DisallowHeapAllocation no_gc; + + struct Entry { + Name key; + Object value; + PropertyDetails details; + }; + + if (Capacity() == 0) return; + + Entry dummy{Name(), Object(), PropertyDetails::Empty()}; + std::vector data(NumberOfElements(), dummy); + + ReadOnlyRoots roots(isolate); + int data_index = 0; + for (int enum_index = 0; enum_index < UsedCapacity(); ++enum_index) { + int entry = EntryForEnumerationIndex(enum_index); + Object key; + if (!ToKey(roots, entry, &key)) continue; + + data[data_index++] = + Entry{Name::cast(key), ValueAtRaw(entry), DetailsAt(entry)}; + } + + Initialize(isolate, meta_table(), Capacity()); + + int new_enum_index = 0; + SetNumberOfElements(static_cast(data.size())); + for (Entry& e : data) { + int new_entry = AddInternal(e.key, e.value, e.details); + + // TODO(v8::11388) Investigate ways of hoisting the branching needed to + // select the correct meta table entry size (based on the capacity of the + // table) out of the loop. + SetEntryForEnumerationIndex(new_enum_index, new_entry); + ++new_enum_index; + } +} + // The largest value we ever have to store in the enumeration table is // Capacity() - 1. The largest value we ever have to store for the present or // deleted element count is MaxUsableCapacity(Capacity()). All data in the diff --git a/src/objects/swiss-name-dictionary.h b/src/objects/swiss-name-dictionary.h index acbb10cf0e..516374b6b7 100644 --- a/src/objects/swiss-name-dictionary.h +++ b/src/objects/swiss-name-dictionary.h @@ -119,6 +119,7 @@ class SwissNameDictionary : public HeapObject { static Handle Rehash(LocalIsolate* isolate, Handle table, int new_capacity); + void Rehash(Isolate* isolate); inline void SetHash(int hash); inline int Hash();