From 3d52c3253758842e1091277098a93564159a486c Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 30 Apr 2020 15:59:11 +0800 Subject: [PATCH] [snapshot] rehash JSMap and JSSet during deserialization --- deps/v8/src/objects/heap-object.h | 2 +- deps/v8/src/objects/objects.cc | 31 ++++++++++++++++++-- deps/v8/src/objects/ordered-hash-table.cc | 17 +++++++++++ deps/v8/src/objects/ordered-hash-table.h | 6 ++++ deps/v8/src/snapshot/deserializer.cc | 14 ++++++++- deps/v8/src/snapshot/deserializer.h | 2 ++ deps/v8/src/snapshot/partial-deserializer.cc | 2 +- deps/v8/test/cctest/test-serialize.cc | 12 +++++--- 8 files changed, 76 insertions(+), 10 deletions(-) diff --git a/deps/v8/src/objects/heap-object.h b/deps/v8/src/objects/heap-object.h index fcbb0ce8336bb7..1811502b608d87 100644 --- a/deps/v8/src/objects/heap-object.h +++ b/deps/v8/src/objects/heap-object.h @@ -190,7 +190,7 @@ class HeapObject : public Object { bool CanBeRehashed() const; // Rehash the object based on the layout inferred from its map. - void RehashBasedOnMap(ReadOnlyRoots root); + void RehashBasedOnMap(Isolate* isolate, ReadOnlyRoots root); // Layout description. #define HEAP_OBJECT_FIELDS(V) \ diff --git a/deps/v8/src/objects/objects.cc b/deps/v8/src/objects/objects.cc index 9b53019297a3c6..2c15490c83f3ef 100644 --- a/deps/v8/src/objects/objects.cc +++ b/deps/v8/src/objects/objects.cc @@ -2285,9 +2285,9 @@ bool HeapObject::NeedsRehashing() const { case TRANSITION_ARRAY_TYPE: return TransitionArray::cast(*this).number_of_entries() > 1; case ORDERED_HASH_MAP_TYPE: - return OrderedHashMap::cast(*this).NumberOfElements() > 0; + return false; // We'll rehash from the JSMap referecing it case ORDERED_HASH_SET_TYPE: - return OrderedHashSet::cast(*this).NumberOfElements() > 0; + return false; // We'll rehash from the JSSap referecing it case NAME_DICTIONARY_TYPE: case GLOBAL_DICTIONARY_TYPE: case NUMBER_DICTIONARY_TYPE: @@ -2297,6 +2297,8 @@ bool HeapObject::NeedsRehashing() const { case SMALL_ORDERED_HASH_MAP_TYPE: case SMALL_ORDERED_HASH_SET_TYPE: case SMALL_ORDERED_NAME_DICTIONARY_TYPE: + case JS_MAP_TYPE: + case JS_SET_TYPE: return true; default: return false; @@ -2306,8 +2308,12 @@ bool HeapObject::NeedsRehashing() const { bool HeapObject::CanBeRehashed() const { DCHECK(NeedsRehashing()); switch (map().instance_type()) { + case JS_MAP_TYPE: + case JS_SET_TYPE: + return true; case ORDERED_HASH_MAP_TYPE: case ORDERED_HASH_SET_TYPE: + UNREACHABLE(); // We'll rehash from the JSMap or JSSet referecing them case ORDERED_NAME_DICTIONARY_TYPE: // TODO(yangguo): actually support rehashing OrderedHash{Map,Set}. return false; @@ -2333,7 +2339,7 @@ bool HeapObject::CanBeRehashed() const { return false; } -void HeapObject::RehashBasedOnMap(ReadOnlyRoots roots) { +void HeapObject::RehashBasedOnMap(Isolate* isolate, ReadOnlyRoots roots) { switch (map().instance_type()) { case HASH_TABLE_TYPE: UNREACHABLE(); @@ -2365,6 +2371,25 @@ void HeapObject::RehashBasedOnMap(ReadOnlyRoots roots) { case SMALL_ORDERED_HASH_SET_TYPE: DCHECK_EQ(0, SmallOrderedHashSet::cast(*this).NumberOfElements()); break; + case ORDERED_HASH_MAP_TYPE: + case ORDERED_HASH_SET_TYPE: + UNREACHABLE(); // We'll rehash from the JSMap or JSSet referecing them + case JS_MAP_TYPE: { + JSMap map = JSMap::cast(*this); + Handle table(OrderedHashMap::cast(map.table()), isolate); + Handle new_table = + OrderedHashMap::Rehash(isolate, table).ToHandleChecked(); + map.set_table(*new_table); + break; + } + case JS_SET_TYPE: { + JSSet set = JSSet::cast(*this); + Handle table(OrderedHashSet::cast(set.table()), isolate); + Handle new_table = + OrderedHashSet::Rehash(isolate, table).ToHandleChecked(); + set.set_table(*new_table); + break; + } case SMALL_ORDERED_NAME_DICTIONARY_TYPE: DCHECK_EQ(0, SmallOrderedNameDictionary::cast(*this).NumberOfElements()); break; diff --git a/deps/v8/src/objects/ordered-hash-table.cc b/deps/v8/src/objects/ordered-hash-table.cc index 962224024ea805..9fa427a379ed15 100644 --- a/deps/v8/src/objects/ordered-hash-table.cc +++ b/deps/v8/src/objects/ordered-hash-table.cc @@ -193,6 +193,13 @@ HeapObject OrderedHashMap::GetEmpty(ReadOnlyRoots ro_roots) { return ro_roots.empty_ordered_hash_map(); } +template +MaybeHandle OrderedHashTable::Rehash( + Isolate* isolate, Handle table) { + return OrderedHashTable::Rehash(isolate, table, + table->Capacity()); +} + template MaybeHandle OrderedHashTable::Rehash( Isolate* isolate, Handle table, int new_capacity) { @@ -249,6 +256,16 @@ MaybeHandle OrderedHashSet::Rehash(Isolate* isolate, new_capacity); } +MaybeHandle OrderedHashSet::Rehash( + Isolate* isolate, Handle table) { + return OrderedHashTable::Rehash(isolate, table); +} + +MaybeHandle OrderedHashMap::Rehash( + Isolate* isolate, Handle table) { + return OrderedHashTable::Rehash(isolate, table); +} + MaybeHandle OrderedHashMap::Rehash(Isolate* isolate, Handle table, int new_capacity) { diff --git a/deps/v8/src/objects/ordered-hash-table.h b/deps/v8/src/objects/ordered-hash-table.h index 590846f1302775..8e0d3a8ee576af 100644 --- a/deps/v8/src/objects/ordered-hash-table.h +++ b/deps/v8/src/objects/ordered-hash-table.h @@ -200,6 +200,8 @@ class OrderedHashTable : public FixedArray { static MaybeHandle Allocate( Isolate* isolate, int capacity, AllocationType allocation = AllocationType::kYoung); + + static MaybeHandle Rehash(Isolate* isolate, Handle table); static MaybeHandle Rehash(Isolate* isolate, Handle table, int new_capacity); @@ -244,6 +246,8 @@ class V8_EXPORT_PRIVATE OrderedHashSet static MaybeHandle Rehash(Isolate* isolate, Handle table, int new_capacity); + static MaybeHandle Rehash(Isolate* isolate, + Handle table); static MaybeHandle Allocate( Isolate* isolate, int capacity, AllocationType allocation = AllocationType::kYoung); @@ -273,6 +277,8 @@ class V8_EXPORT_PRIVATE OrderedHashMap static MaybeHandle Rehash(Isolate* isolate, Handle table, int new_capacity); + static MaybeHandle Rehash(Isolate* isolate, + Handle table); Object ValueAt(int entry); // This takes and returns raw Address values containing tagged Object diff --git a/deps/v8/src/snapshot/deserializer.cc b/deps/v8/src/snapshot/deserializer.cc index 127cfae29e018c..1c4e6e22e05733 100644 --- a/deps/v8/src/snapshot/deserializer.cc +++ b/deps/v8/src/snapshot/deserializer.cc @@ -70,7 +70,7 @@ void Deserializer::Initialize(Isolate* isolate) { void Deserializer::Rehash() { DCHECK(can_rehash() || deserializing_user_code()); for (HeapObject item : to_rehash_) { - item.RehashBasedOnMap(ReadOnlyRoots(isolate_)); + item.RehashBasedOnMap(isolate_, ReadOnlyRoots(isolate_)); } } @@ -130,6 +130,13 @@ void Deserializer::DeserializeDeferredObjects() { } } } + + // When the deserialization of maps are deferred, they will be created + // as filler maps, and we postpone the post processing until the maps + // are also deserialized. + for (auto pair : fillers_to_post_process_) { + PostProcessNewObject(pair.first, pair.second); + } } void Deserializer::LogNewObjectEvents() { @@ -201,6 +208,11 @@ HeapObject Deserializer::PostProcessNewObject(HeapObject obj, DisallowHeapAllocation no_gc; if ((FLAG_rehash_snapshot && can_rehash_) || deserializing_user_code()) { + if (obj.IsFiller()) { + CHECK_EQ(fillers_to_post_process_.find(obj), fillers_to_post_process_.end()); + fillers_to_post_process_.insert({obj, space}); + } + if (obj.IsString()) { // Uninitialize hash field as we need to recompute the hash. String string = String::cast(obj); diff --git a/deps/v8/src/snapshot/deserializer.h b/deps/v8/src/snapshot/deserializer.h index 3aac06ba7e633c..dd81af54b73435 100644 --- a/deps/v8/src/snapshot/deserializer.h +++ b/deps/v8/src/snapshot/deserializer.h @@ -194,6 +194,8 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer { // TODO(6593): generalize rehashing, and remove this flag. bool can_rehash_; std::vector to_rehash_; + std::unordered_map + fillers_to_post_process_; #ifdef DEBUG uint32_t num_api_references_; diff --git a/deps/v8/src/snapshot/partial-deserializer.cc b/deps/v8/src/snapshot/partial-deserializer.cc index 8a215b6b871e94..e15cf6c678fbb8 100644 --- a/deps/v8/src/snapshot/partial-deserializer.cc +++ b/deps/v8/src/snapshot/partial-deserializer.cc @@ -57,12 +57,12 @@ MaybeHandle PartialDeserializer::Deserialize( // new code, which also has to be flushed from instruction cache. CHECK_EQ(start_address, code_space->top()); - if (FLAG_rehash_snapshot && can_rehash()) Rehash(); LogNewMapEvents(); result = handle(root, isolate); } + if (FLAG_rehash_snapshot && can_rehash()) Rehash(); SetupOffHeapArrayBufferBackingStores(); return result; diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc index f37b6235041aaa..93275dfe957238 100644 --- a/deps/v8/test/cctest/test-serialize.cc +++ b/deps/v8/test/cctest/test-serialize.cc @@ -3715,7 +3715,7 @@ UNINITIALIZED_TEST(SnapshotCreatorIncludeGlobalProxy) { FreeCurrentEmbeddedBlob(); } -UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) { +UNINITIALIZED_TEST(ReinitializeHashSeedJSCollectionRehashable) { DisableAlwaysOpt(); i::FLAG_rehash_snapshot = true; i::FLAG_hash_seed = 42; @@ -3733,13 +3733,16 @@ UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) { CompileRun( "var m = new Map();" "m.set('a', 1);" - "m.set('b', 2);"); + "m.set('b', 2);" + "var s = new Set();" + "s.add(1)"); ExpectInt32("m.get('b')", 2); + ExpectTrue("s.has(1)"); creator.SetDefaultContext(context); } blob = creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear); - CHECK(!blob.CanBeRehashed()); + CHECK(blob.CanBeRehashed()); } ReadOnlyHeap::ClearSharedHeapForTest(); @@ -3750,7 +3753,7 @@ UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) { v8::Isolate* isolate = v8::Isolate::New(create_params); { // Check that no rehashing has been performed. - CHECK_EQ(static_cast(42), + CHECK_EQ(static_cast(1337), HashSeed(reinterpret_cast(isolate))); v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); @@ -3758,6 +3761,7 @@ UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) { CHECK(!context.IsEmpty()); v8::Context::Scope context_scope(context); ExpectInt32("m.get('b')", 2); + ExpectTrue("s.has(1)"); } isolate->Dispose(); delete[] blob.data;