Commit f7771e5b authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[runtime] Recompute enumeration indices of dictionaries upon bitfield overflow

Otherwise we'll get weird semantics when enumerating objects after many
deletes/reinserts.

Bug: chromium:1033771
Change-Id: If0a459169c3794a30d9632d09e80da3cfcd4302c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1993966
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarVictor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65690}
parent 4453f89c
...@@ -65,13 +65,13 @@ BaseNameDictionary<Derived, Shape>::BaseNameDictionary(Address ptr) ...@@ -65,13 +65,13 @@ BaseNameDictionary<Derived, Shape>::BaseNameDictionary(Address ptr)
: Dictionary<Derived, Shape>(ptr) {} : Dictionary<Derived, Shape>(ptr) {}
template <typename Derived, typename Shape> template <typename Derived, typename Shape>
void BaseNameDictionary<Derived, Shape>::SetNextEnumerationIndex(int index) { void BaseNameDictionary<Derived, Shape>::set_next_enumeration_index(int index) {
DCHECK_NE(0, index); DCHECK_LT(0, index);
this->set(kNextEnumerationIndexIndex, Smi::FromInt(index)); this->set(kNextEnumerationIndexIndex, Smi::FromInt(index));
} }
template <typename Derived, typename Shape> template <typename Derived, typename Shape>
int BaseNameDictionary<Derived, Shape>::NextEnumerationIndex() { int BaseNameDictionary<Derived, Shape>::next_enumeration_index() {
return Smi::ToInt(this->get(kNextEnumerationIndexIndex)); return Smi::ToInt(this->get(kNextEnumerationIndexIndex));
} }
......
...@@ -125,10 +125,6 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) BaseNameDictionary ...@@ -125,10 +125,6 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) BaseNameDictionary
static const int kObjectHashIndex = kNextEnumerationIndexIndex + 1; static const int kObjectHashIndex = kNextEnumerationIndexIndex + 1;
static const int kEntryValueIndex = 1; static const int kEntryValueIndex = 1;
// Accessors for next enumeration index.
inline void SetNextEnumerationIndex(int index);
inline int NextEnumerationIndex();
inline void SetHash(int hash); inline void SetHash(int hash);
inline int Hash() const; inline int Hash() const;
...@@ -143,6 +139,13 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) BaseNameDictionary ...@@ -143,6 +139,13 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) BaseNameDictionary
V8_WARN_UNUSED_RESULT static ExceptionStatus CollectKeysTo( V8_WARN_UNUSED_RESULT static ExceptionStatus CollectKeysTo(
Handle<Derived> dictionary, KeyAccumulator* keys); Handle<Derived> dictionary, KeyAccumulator* keys);
// Allocate the next enumeration index. Possibly updates all enumeration
// indices in the table.
static int NextEnumerationIndex(Isolate* isolate, Handle<Derived> dictionary);
// Accessors for next enumeration index.
inline int next_enumeration_index();
inline void set_next_enumeration_index(int index);
// Return the key indices sorted by its enumeration index. // Return the key indices sorted by its enumeration index.
static Handle<FixedArray> IterationIndices(Isolate* isolate, static Handle<FixedArray> IterationIndices(Isolate* isolate,
Handle<Derived> dictionary); Handle<Derived> dictionary);
...@@ -154,10 +157,6 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) BaseNameDictionary ...@@ -154,10 +157,6 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) BaseNameDictionary
Handle<FixedArray> storage, KeyCollectionMode mode, Handle<FixedArray> storage, KeyCollectionMode mode,
KeyAccumulator* accumulator); KeyAccumulator* accumulator);
// Ensure enough space for n additional elements.
static Handle<Derived> EnsureCapacity(Isolate* isolate,
Handle<Derived> dictionary, int n);
V8_WARN_UNUSED_RESULT static Handle<Derived> AddNoUpdateNextEnumerationIndex( V8_WARN_UNUSED_RESULT static Handle<Derived> AddNoUpdateNextEnumerationIndex(
Isolate* isolate, Handle<Derived> dictionary, Key key, Isolate* isolate, Handle<Derived> dictionary, Key key,
Handle<Object> value, PropertyDetails details, Handle<Object> value, PropertyDetails details,
......
...@@ -192,7 +192,7 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) HashTable ...@@ -192,7 +192,7 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) HashTable
// Ensure enough space for n additional elements. // Ensure enough space for n additional elements.
V8_WARN_UNUSED_RESULT static Handle<Derived> EnsureCapacity( V8_WARN_UNUSED_RESULT static Handle<Derived> EnsureCapacity(
Isolate* isolate, Handle<Derived> table, int n, Isolate* isolate, Handle<Derived> table, int n = 1,
AllocationType allocation = AllocationType::kYoung); AllocationType allocation = AllocationType::kYoung);
// Returns true if this table has sufficient capacity for adding n elements. // Returns true if this table has sufficient capacity for adding n elements.
......
...@@ -2910,7 +2910,7 @@ void MigrateFastToSlow(Isolate* isolate, Handle<JSObject> object, ...@@ -2910,7 +2910,7 @@ void MigrateFastToSlow(Isolate* isolate, Handle<JSObject> object,
} }
// Copy the next enumeration index from instance descriptor. // Copy the next enumeration index from instance descriptor.
dictionary->SetNextEnumerationIndex(real_size + 1); dictionary->set_next_enumeration_index(real_size + 1);
// From here on we cannot fail and we shouldn't GC anymore. // From here on we cannot fail and we shouldn't GC anymore.
DisallowHeapAllocation no_allocation; DisallowHeapAllocation no_allocation;
......
...@@ -365,7 +365,7 @@ class ObjectDescriptor { ...@@ -365,7 +365,7 @@ class ObjectDescriptor {
void Finalize(Isolate* isolate) { void Finalize(Isolate* isolate) {
if (HasDictionaryProperties()) { if (HasDictionaryProperties()) {
properties_dictionary_template_->SetNextEnumerationIndex( properties_dictionary_template_->set_next_enumeration_index(
next_enumeration_index_); next_enumeration_index_);
computed_properties_ = FixedArray::ShrinkOrEmpty( computed_properties_ = FixedArray::ShrinkOrEmpty(
isolate, computed_properties_, current_computed_index_); isolate, computed_properties_, current_computed_index_);
......
...@@ -589,8 +589,8 @@ void LookupIterator::PrepareTransitionToDataProperty( ...@@ -589,8 +589,8 @@ void LookupIterator::PrepareTransitionToDataProperty(
transition_ = cell; transition_ = cell;
// Assign an enumeration index to the property and update // Assign an enumeration index to the property and update
// SetNextEnumerationIndex. // SetNextEnumerationIndex.
int index = dictionary->NextEnumerationIndex(); int index = GlobalDictionary::NextEnumerationIndex(isolate_, dictionary);
dictionary->SetNextEnumerationIndex(index + 1); dictionary->set_next_enumeration_index(index + 1);
property_details_ = PropertyDetails( property_details_ = PropertyDetails(
kData, attributes, PropertyCellType::kUninitialized, index); kData, attributes, PropertyCellType::kUninitialized, index);
PropertyCellType new_type = PropertyCellType new_type =
......
...@@ -6686,7 +6686,7 @@ void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, ...@@ -6686,7 +6686,7 @@ void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
int expected) { int expected) {
Handle<StringTable> table = isolate->factory()->string_table(); Handle<StringTable> table = isolate->factory()->string_table();
// We need a key instance for the virtual hash function. // We need a key instance for the virtual hash function.
table = StringTable::EnsureCapacity(isolate, table, expected); table = EnsureCapacity(isolate, table, expected);
isolate->heap()->SetRootStringTable(*table); isolate->heap()->SetRootStringTable(*table);
} }
...@@ -6738,7 +6738,7 @@ Handle<String> StringTable::LookupKey(Isolate* isolate, StringTableKey* key) { ...@@ -6738,7 +6738,7 @@ Handle<String> StringTable::LookupKey(Isolate* isolate, StringTableKey* key) {
table = StringTable::CautiousShrink(isolate, table); table = StringTable::CautiousShrink(isolate, table);
// Adding new string. Grow table if needed. // Adding new string. Grow table if needed.
table = StringTable::EnsureCapacity(isolate, table, 1); table = EnsureCapacity(isolate, table);
isolate->heap()->SetRootStringTable(*table); isolate->heap()->SetRootStringTable(*table);
return AddKeyNoResize(isolate, key); return AddKeyNoResize(isolate, key);
...@@ -6880,7 +6880,7 @@ Handle<StringSet> StringSet::New(Isolate* isolate) { ...@@ -6880,7 +6880,7 @@ Handle<StringSet> StringSet::New(Isolate* isolate) {
Handle<StringSet> StringSet::Add(Isolate* isolate, Handle<StringSet> stringset, Handle<StringSet> StringSet::Add(Isolate* isolate, Handle<StringSet> stringset,
Handle<String> name) { Handle<String> name) {
if (!stringset->Has(isolate, name)) { if (!stringset->Has(isolate, name)) {
stringset = EnsureCapacity(isolate, stringset, 1); stringset = EnsureCapacity(isolate, stringset);
uint32_t hash = ShapeT::Hash(isolate, *name); uint32_t hash = ShapeT::Hash(isolate, *name);
InternalIndex entry = stringset->FindInsertionEntry(hash); InternalIndex entry = stringset->FindInsertionEntry(hash);
stringset->set(EntryToIndex(entry), *name); stringset->set(EntryToIndex(entry), *name);
...@@ -6898,7 +6898,7 @@ Handle<ObjectHashSet> ObjectHashSet::Add(Isolate* isolate, ...@@ -6898,7 +6898,7 @@ Handle<ObjectHashSet> ObjectHashSet::Add(Isolate* isolate,
Handle<Object> key) { Handle<Object> key) {
int32_t hash = key->GetOrCreateHash(isolate).value(); int32_t hash = key->GetOrCreateHash(isolate).value();
if (!set->Has(isolate, key, hash)) { if (!set->Has(isolate, key, hash)) {
set = EnsureCapacity(isolate, set, 1); set = EnsureCapacity(isolate, set);
InternalIndex entry = set->FindInsertionEntry(hash); InternalIndex entry = set->FindInsertionEntry(hash);
set->set(EntryToIndex(entry), *key); set->set(EntryToIndex(entry), *key);
set->ElementAdded(); set->ElementAdded();
...@@ -7094,7 +7094,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutScript( ...@@ -7094,7 +7094,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
src = String::Flatten(isolate, src); src = String::Flatten(isolate, src);
StringSharedKey key(src, shared, language_mode, kNoSourcePosition); StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
Handle<Object> k = key.AsHandle(isolate); Handle<Object> k = key.AsHandle(isolate);
cache = EnsureCapacity(isolate, cache, 1); cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(key.Hash()); InternalIndex entry = cache->FindInsertionEntry(key.Hash());
cache->set(EntryToIndex(entry), *k); cache->set(EntryToIndex(entry), *k);
cache->set(EntryToIndex(entry) + 1, *value); cache->set(EntryToIndex(entry) + 1, *value);
...@@ -7126,7 +7126,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutEval( ...@@ -7126,7 +7126,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
} }
} }
cache = EnsureCapacity(isolate, cache, 1); cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(key.Hash()); InternalIndex entry = cache->FindInsertionEntry(key.Hash());
Handle<Object> k = Handle<Object> k =
isolate->factory()->NewNumber(static_cast<double>(key.Hash())); isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
...@@ -7140,7 +7140,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp( ...@@ -7140,7 +7140,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src, Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src,
JSRegExp::Flags flags, Handle<FixedArray> value) { JSRegExp::Flags flags, Handle<FixedArray> value) {
RegExpKey key(src, flags); RegExpKey key(src, flags);
cache = EnsureCapacity(isolate, cache, 1); cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(key.Hash()); InternalIndex entry = cache->FindInsertionEntry(key.Hash());
// We store the value in the key slot, and compare the search key // We store the value in the key slot, and compare the search key
// to the stored value with a custon IsMatch function during lookups. // to the stored value with a custon IsMatch function during lookups.
...@@ -7202,15 +7202,16 @@ Handle<Derived> BaseNameDictionary<Derived, Shape>::New( ...@@ -7202,15 +7202,16 @@ Handle<Derived> BaseNameDictionary<Derived, Shape>::New(
Handle<Derived> dict = Dictionary<Derived, Shape>::New( Handle<Derived> dict = Dictionary<Derived, Shape>::New(
isolate, at_least_space_for, allocation, capacity_option); isolate, at_least_space_for, allocation, capacity_option);
dict->SetHash(PropertyArray::kNoHashSentinel); dict->SetHash(PropertyArray::kNoHashSentinel);
dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex); dict->set_next_enumeration_index(PropertyDetails::kInitialIndex);
return dict; return dict;
} }
template <typename Derived, typename Shape> template <typename Derived, typename Shape>
Handle<Derived> BaseNameDictionary<Derived, Shape>::EnsureCapacity( int BaseNameDictionary<Derived, Shape>::NextEnumerationIndex(
Isolate* isolate, Handle<Derived> dictionary, int n) { Isolate* isolate, Handle<Derived> dictionary) {
// Check whether there are enough enumeration indices to add n elements. int index = dictionary->next_enumeration_index();
if (!PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) { // Check whether the next enumeration index is valid.
if (!PropertyDetails::IsValidIndex(index)) {
// If not, we generate new indices for the properties. // If not, we generate new indices for the properties.
int length = dictionary->NumberOfElements(); int length = dictionary->NumberOfElements();
...@@ -7231,11 +7232,12 @@ Handle<Derived> BaseNameDictionary<Derived, Shape>::EnsureCapacity( ...@@ -7231,11 +7232,12 @@ Handle<Derived> BaseNameDictionary<Derived, Shape>::EnsureCapacity(
dictionary->DetailsAtPut(isolate, index, new_details); dictionary->DetailsAtPut(isolate, index, new_details);
} }
// Set the next enumeration index. index = PropertyDetails::kInitialIndex + length;
dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex +
length);
} }
return HashTable<Derived, Shape>::EnsureCapacity(isolate, dictionary, n);
// Don't update the next enumeration index here, since we might be looking at
// an immutable empty dictionary.
return index;
} }
template <typename Derived, typename Shape> template <typename Derived, typename Shape>
...@@ -7284,13 +7286,13 @@ Handle<Derived> BaseNameDictionary<Derived, Shape>::Add( ...@@ -7284,13 +7286,13 @@ Handle<Derived> BaseNameDictionary<Derived, Shape>::Add(
DCHECK_EQ(0, details.dictionary_index()); DCHECK_EQ(0, details.dictionary_index());
// Assign an enumeration index to the property and update // Assign an enumeration index to the property and update
// SetNextEnumerationIndex. // SetNextEnumerationIndex.
int index = dictionary->NextEnumerationIndex(); int index = Derived::NextEnumerationIndex(isolate, dictionary);
details = details.set_index(index); details = details.set_index(index);
dictionary = AddNoUpdateNextEnumerationIndex(isolate, dictionary, key, value, dictionary = AddNoUpdateNextEnumerationIndex(isolate, dictionary, key, value,
details, entry_out); details, entry_out);
// Update enumeration index here in order to avoid potential modification of // Update enumeration index here in order to avoid potential modification of
// the canonical empty dictionary which lives in read only space. // the canonical empty dictionary which lives in read only space.
dictionary->SetNextEnumerationIndex(index + 1); dictionary->set_next_enumeration_index(index + 1);
return dictionary; return dictionary;
} }
...@@ -7304,7 +7306,7 @@ Handle<Derived> Dictionary<Derived, Shape>::Add(Isolate* isolate, ...@@ -7304,7 +7306,7 @@ Handle<Derived> Dictionary<Derived, Shape>::Add(Isolate* isolate,
// Validate that the key is absent. // Validate that the key is absent.
SLOW_DCHECK(dictionary->FindEntry(isolate, key).is_not_found()); SLOW_DCHECK(dictionary->FindEntry(isolate, key).is_not_found());
// Check whether the dictionary should be extended. // Check whether the dictionary should be extended.
dictionary = Derived::EnsureCapacity(isolate, dictionary, 1); dictionary = Derived::EnsureCapacity(isolate, dictionary);
// Compute the key object. // Compute the key object.
Handle<Object> k = Shape::AsHandle(isolate, key); Handle<Object> k = Shape::AsHandle(isolate, key);
...@@ -7651,7 +7653,7 @@ Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Isolate* isolate, ...@@ -7651,7 +7653,7 @@ Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Isolate* isolate,
} }
// Check whether the hash table should be extended. // Check whether the hash table should be extended.
table = Derived::EnsureCapacity(isolate, table, 1); table = Derived::EnsureCapacity(isolate, table);
table->AddEntry(table->FindInsertionEntry(hash), *key, *value); table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
return table; return table;
} }
...@@ -7900,8 +7902,8 @@ Handle<PropertyCell> PropertyCell::PrepareForValue( ...@@ -7900,8 +7902,8 @@ Handle<PropertyCell> PropertyCell::PrepareForValue(
// Preserve the enumeration index unless the property was deleted or never // Preserve the enumeration index unless the property was deleted or never
// initialized. // initialized.
if (cell->value().IsTheHole(isolate)) { if (cell->value().IsTheHole(isolate)) {
index = dictionary->NextEnumerationIndex(); index = GlobalDictionary::NextEnumerationIndex(isolate, dictionary);
dictionary->SetNextEnumerationIndex(index + 1); dictionary->set_next_enumeration_index(index + 1);
} else { } else {
index = original_details.dictionary_index(); index = original_details.dictionary_index();
} }
......
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