diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 6dec886a194a82..51993f3f329ca5 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -17389,7 +17389,7 @@ Handle HashTable::EnsureCapacity( int capacity = table->Capacity(); int nof = table->NumberOfElements() + n; - if (table->HasSufficientCapacity(n)) return table; + if (table->HasSufficientCapacityToAdd(n)) return table; const int kMinCapacityForPretenure = 256; bool should_pretenure = pretenure == TENURED || @@ -17405,16 +17405,16 @@ Handle HashTable::EnsureCapacity( return new_table; } - template -bool HashTable::HasSufficientCapacity(int n) { +bool HashTable::HasSufficientCapacityToAdd( + int number_of_additional_elements) { int capacity = Capacity(); - int nof = NumberOfElements() + n; + int nof = NumberOfElements() + number_of_additional_elements; int nod = NumberOfDeletedElements(); // Return true if: - // 50% is still free after adding n elements and + // 50% is still free after adding number_of_additional_elements elements and // at most 50% of the free elements are deleted elements. - if (nod <= (capacity - nof) >> 1) { + if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) { int needed_free = nof >> 1; if (nof + needed_free <= capacity) return true; } @@ -18332,7 +18332,7 @@ void Dictionary::SetRequiresCopyOnCapacityChange() { DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements()); // Make sure that HashTable::EnsureCapacity will create a copy. DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity()); - DCHECK(!DerivedHashTable::HasSufficientCapacity(1)); + DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1)); } @@ -18740,6 +18740,19 @@ Handle ObjectHashTable::Put(Handle table, if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) { table->Rehash(isolate->factory()->undefined_value()); } + // If we're out of luck, we didn't get a GC recently, and so rehashing + // isn't enough to avoid a crash. + if (!table->HasSufficientCapacityToAdd(1)) { + int nof = table->NumberOfElements() + 1; + int capacity = ObjectHashTable::ComputeCapacity(nof * 2); + if (capacity > ObjectHashTable::kMaxCapacity) { + for (size_t i = 0; i < 2; ++i) { + isolate->heap()->CollectAllGarbage( + Heap::kFinalizeIncrementalMarkingMask, "full object hash table"); + } + table->Rehash(isolate->factory()->undefined_value()); + } + } // Check whether the hash table should be extended. table = EnsureCapacity(table, 1, key); diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index c825b42d844104..abced2d4bad50c 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -3331,7 +3331,7 @@ class HashTable : public HashTableBase { PretenureFlag pretenure = NOT_TENURED); // Returns true if this table has sufficient capacity for adding n elements. - bool HasSufficientCapacity(int n); + bool HasSufficientCapacityToAdd(int number_of_additional_elements); // Sets the capacity of the hash table. void SetCapacity(int capacity) {