Skip to content

Commit 22014de

Browse files
joyeecheungCommit Bot
authored andcommitted
Reland "[snapshot] rehash JSMap and JSSet during deserialization"
This is a reland of 8374fee. Fixed rehashing of global proxy keys by creating its identity hash early, before the deserialization of the context snapshot. Original change's description: > [snapshot] rehash JSMap and JSSet during deserialization > > To rehash JSMap and JSSet, we simply replace the backing store > with a new one created with the new hash. > > Bug: v8:9187 > Change-Id: I90c25b18b33b7bc2b6ffe1b89fe17aa5f978b517 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2143983 > Commit-Queue: Joyee Cheung <[email protected]> > Reviewed-by: Jakob Gruber <[email protected]> > Reviewed-by: Camillo Bruni <[email protected]> > Cr-Commit-Position: refs/heads/master@{#67663} Bug: v8:9187, v8:10523 Change-Id: I7a0319b1d10ff07644de902fec43e7c2b1dd8da9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2212085 Reviewed-by: Leszek Swirski <[email protected]> Reviewed-by: Camillo Bruni <[email protected]> Reviewed-by: Jakob Gruber <[email protected]> Commit-Queue: Joyee Cheung <[email protected]> Cr-Commit-Position: refs/heads/master@{#67999}
1 parent 5df2f65 commit 22014de

10 files changed

Lines changed: 102 additions & 12 deletions

File tree

src/heap/factory.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2819,8 +2819,12 @@ Handle<JSGlobalProxy> Factory::NewUninitializedJSGlobalProxy(int size) {
28192819
map->set_is_access_check_needed(true);
28202820
map->set_may_have_interesting_symbols(true);
28212821
LOG(isolate(), MapDetails(*map));
2822-
return Handle<JSGlobalProxy>::cast(
2822+
Handle<JSGlobalProxy> proxy = Handle<JSGlobalProxy>::cast(
28232823
NewJSObjectFromMap(map, AllocationType::kYoung));
2824+
// Create identity hash early in case there is any JS collection containing
2825+
// a global proxy key and needs to be rehashed after deserialization.
2826+
proxy->GetOrCreateIdentityHash(isolate());
2827+
return proxy;
28242828
}
28252829

28262830
void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,

src/objects/js-collection.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class JSSet : public TorqueGeneratedJSSet<JSSet, JSCollection> {
3030
public:
3131
static void Initialize(Handle<JSSet> set, Isolate* isolate);
3232
static void Clear(Isolate* isolate, Handle<JSSet> set);
33+
void Rehash(Isolate* isolate);
3334

3435
// Dispatched behavior.
3536
DECL_PRINTER(JSSet)
@@ -56,6 +57,7 @@ class JSMap : public TorqueGeneratedJSMap<JSMap, JSCollection> {
5657
public:
5758
static void Initialize(Handle<JSMap> map, Isolate* isolate);
5859
static void Clear(Isolate* isolate, Handle<JSMap> map);
60+
void Rehash(Isolate* isolate);
5961

6062
// Dispatched behavior.
6163
DECL_PRINTER(JSMap)

src/objects/objects.cc

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2306,9 +2306,8 @@ bool HeapObject::NeedsRehashing() const {
23062306
case TRANSITION_ARRAY_TYPE:
23072307
return TransitionArray::cast(*this).number_of_entries() > 1;
23082308
case ORDERED_HASH_MAP_TYPE:
2309-
return OrderedHashMap::cast(*this).NumberOfElements() > 0;
23102309
case ORDERED_HASH_SET_TYPE:
2311-
return OrderedHashSet::cast(*this).NumberOfElements() > 0;
2310+
return false; // We'll rehash from the JSMap or JSSet referencing them.
23122311
case NAME_DICTIONARY_TYPE:
23132312
case GLOBAL_DICTIONARY_TYPE:
23142313
case NUMBER_DICTIONARY_TYPE:
@@ -2318,6 +2317,8 @@ bool HeapObject::NeedsRehashing() const {
23182317
case SMALL_ORDERED_HASH_MAP_TYPE:
23192318
case SMALL_ORDERED_HASH_SET_TYPE:
23202319
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
2320+
case JS_MAP_TYPE:
2321+
case JS_SET_TYPE:
23212322
return true;
23222323
default:
23232324
return false;
@@ -2327,10 +2328,13 @@ bool HeapObject::NeedsRehashing() const {
23272328
bool HeapObject::CanBeRehashed() const {
23282329
DCHECK(NeedsRehashing());
23292330
switch (map().instance_type()) {
2331+
case JS_MAP_TYPE:
2332+
case JS_SET_TYPE:
2333+
return true;
23302334
case ORDERED_HASH_MAP_TYPE:
23312335
case ORDERED_HASH_SET_TYPE:
2336+
UNREACHABLE(); // We'll rehash from the JSMap or JSSet referencing them.
23322337
case ORDERED_NAME_DICTIONARY_TYPE:
2333-
// TODO(yangguo): actually support rehashing OrderedHash{Map,Set}.
23342338
return false;
23352339
case NAME_DICTIONARY_TYPE:
23362340
case GLOBAL_DICTIONARY_TYPE:
@@ -2387,6 +2391,19 @@ void HeapObject::RehashBasedOnMap(LocalIsolateWrapper isolate) {
23872391
case SMALL_ORDERED_HASH_SET_TYPE:
23882392
DCHECK_EQ(0, SmallOrderedHashSet::cast(*this).NumberOfElements());
23892393
break;
2394+
case ORDERED_HASH_MAP_TYPE:
2395+
case ORDERED_HASH_SET_TYPE:
2396+
UNREACHABLE(); // We'll rehash from the JSMap or JSSet referencing them.
2397+
case JS_MAP_TYPE: {
2398+
DCHECK(isolate.is_main_thread());
2399+
JSMap::cast(*this).Rehash(isolate.main_thread());
2400+
break;
2401+
}
2402+
case JS_SET_TYPE: {
2403+
DCHECK(isolate.is_main_thread());
2404+
JSSet::cast(*this).Rehash(isolate.main_thread());
2405+
break;
2406+
}
23902407
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
23912408
DCHECK_EQ(0, SmallOrderedNameDictionary::cast(*this).NumberOfElements());
23922409
break;
@@ -7863,6 +7880,13 @@ void JSSet::Clear(Isolate* isolate, Handle<JSSet> set) {
78637880
set->set_table(*table);
78647881
}
78657882

7883+
void JSSet::Rehash(Isolate* isolate) {
7884+
Handle<OrderedHashSet> table_handle(OrderedHashSet::cast(table()), isolate);
7885+
Handle<OrderedHashSet> new_table =
7886+
OrderedHashSet::Rehash(isolate, table_handle).ToHandleChecked();
7887+
set_table(*new_table);
7888+
}
7889+
78667890
void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
78677891
Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
78687892
map->set_table(*table);
@@ -7874,6 +7898,13 @@ void JSMap::Clear(Isolate* isolate, Handle<JSMap> map) {
78747898
map->set_table(*table);
78757899
}
78767900

7901+
void JSMap::Rehash(Isolate* isolate) {
7902+
Handle<OrderedHashMap> table_handle(OrderedHashMap::cast(table()), isolate);
7903+
Handle<OrderedHashMap> new_table =
7904+
OrderedHashMap::Rehash(isolate, table_handle).ToHandleChecked();
7905+
set_table(*new_table);
7906+
}
7907+
78777908
void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
78787909
Isolate* isolate) {
78797910
Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 0);

src/objects/ordered-hash-table.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,13 @@ HeapObject OrderedHashMap::GetEmpty(ReadOnlyRoots ro_roots) {
194194
return ro_roots.empty_ordered_hash_map();
195195
}
196196

197+
template <class Derived, int entrysize>
198+
MaybeHandle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
199+
Isolate* isolate, Handle<Derived> table) {
200+
return OrderedHashTable<Derived, entrysize>::Rehash(isolate, table,
201+
table->Capacity());
202+
}
203+
197204
template <class Derived, int entrysize>
198205
MaybeHandle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
199206
Isolate* isolate, Handle<Derived> table, int new_capacity) {
@@ -250,6 +257,20 @@ MaybeHandle<OrderedHashSet> OrderedHashSet::Rehash(Isolate* isolate,
250257
new_capacity);
251258
}
252259

260+
MaybeHandle<OrderedHashSet> OrderedHashSet::Rehash(
261+
Isolate* isolate, Handle<OrderedHashSet> table) {
262+
return OrderedHashTable<
263+
OrderedHashSet, OrderedHashSet::kEntrySizeWithoutChain>::Rehash(isolate,
264+
table);
265+
}
266+
267+
MaybeHandle<OrderedHashMap> OrderedHashMap::Rehash(
268+
Isolate* isolate, Handle<OrderedHashMap> table) {
269+
return OrderedHashTable<
270+
OrderedHashMap, OrderedHashMap::kEntrySizeWithoutChain>::Rehash(isolate,
271+
table);
272+
}
273+
253274
MaybeHandle<OrderedHashMap> OrderedHashMap::Rehash(Isolate* isolate,
254275
Handle<OrderedHashMap> table,
255276
int new_capacity) {

src/objects/ordered-hash-table.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ class OrderedHashTable : public FixedArray {
138138

139139
// The extra +1 is for linking the bucket chains together.
140140
static const int kEntrySize = entrysize + 1;
141+
static const int kEntrySizeWithoutChain = entrysize;
141142
static const int kChainOffset = entrysize;
142143

143144
static const int kNotFound = -1;
@@ -200,6 +201,8 @@ class OrderedHashTable : public FixedArray {
200201
static MaybeHandle<Derived> Allocate(
201202
Isolate* isolate, int capacity,
202203
AllocationType allocation = AllocationType::kYoung);
204+
205+
static MaybeHandle<Derived> Rehash(Isolate* isolate, Handle<Derived> table);
203206
static MaybeHandle<Derived> Rehash(Isolate* isolate, Handle<Derived> table,
204207
int new_capacity);
205208

@@ -244,6 +247,8 @@ class V8_EXPORT_PRIVATE OrderedHashSet
244247
static MaybeHandle<OrderedHashSet> Rehash(Isolate* isolate,
245248
Handle<OrderedHashSet> table,
246249
int new_capacity);
250+
static MaybeHandle<OrderedHashSet> Rehash(Isolate* isolate,
251+
Handle<OrderedHashSet> table);
247252
static MaybeHandle<OrderedHashSet> Allocate(
248253
Isolate* isolate, int capacity,
249254
AllocationType allocation = AllocationType::kYoung);
@@ -273,6 +278,8 @@ class V8_EXPORT_PRIVATE OrderedHashMap
273278
static MaybeHandle<OrderedHashMap> Rehash(Isolate* isolate,
274279
Handle<OrderedHashMap> table,
275280
int new_capacity);
281+
static MaybeHandle<OrderedHashMap> Rehash(Isolate* isolate,
282+
Handle<OrderedHashMap> table);
276283
Object ValueAt(int entry);
277284

278285
// This takes and returns raw Address values containing tagged Object

src/snapshot/context-deserializer.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ MaybeHandle<Object> ContextDeserializer::Deserialize(
5959
// new code, which also has to be flushed from instruction cache.
6060
CHECK_EQ(start_address, code_space->top());
6161

62-
if (FLAG_rehash_snapshot && can_rehash()) Rehash();
6362
LogNewMapEvents();
6463

6564
result = handle(root, isolate);
6665
}
6766

67+
if (FLAG_rehash_snapshot && can_rehash()) Rehash();
6868
SetupOffHeapArrayBufferBackingStores();
6969

7070
return result;

src/snapshot/deserializer.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ void Deserializer::DeserializeDeferredObjects() {
147147
}
148148
}
149149
}
150+
151+
// When the deserialization of maps are deferred, they will be created
152+
// as filler maps, and we postpone the post processing until the maps
153+
// are also deserialized.
154+
for (const auto& pair : fillers_to_post_process_) {
155+
DCHECK(!pair.first.IsFiller());
156+
PostProcessNewObject(pair.first, pair.second);
157+
}
150158
}
151159

152160
void Deserializer::LogNewMapEvents() {
@@ -208,7 +216,11 @@ HeapObject Deserializer::PostProcessNewObject(HeapObject obj,
208216
DisallowHeapAllocation no_gc;
209217

210218
if ((FLAG_rehash_snapshot && can_rehash_) || deserializing_user_code()) {
211-
if (obj.IsString()) {
219+
if (obj.IsFiller()) {
220+
DCHECK_EQ(fillers_to_post_process_.find(obj),
221+
fillers_to_post_process_.end());
222+
fillers_to_post_process_.insert({obj, space});
223+
} else if (obj.IsString()) {
212224
// Uninitialize hash field as we need to recompute the hash.
213225
String string = String::cast(obj);
214226
string.set_hash_field(String::kEmptyHashField);

src/snapshot/deserializer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,11 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
204204
// TODO(6593): generalize rehashing, and remove this flag.
205205
bool can_rehash_;
206206
std::vector<HeapObject> to_rehash_;
207+
// Store the objects whose maps are deferred and thus initialized as filler
208+
// maps during deserialization, so that they can be processed later when the
209+
// maps become available.
210+
std::unordered_map<HeapObject, SnapshotSpace, Object::Hasher>
211+
fillers_to_post_process_;
207212

208213
#ifdef DEBUG
209214
uint32_t num_api_references_;

src/snapshot/object-deserializer.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,12 @@ MaybeHandle<HeapObject> ObjectDeserializer::Deserialize(
6767
LogNewMapEvents();
6868
}
6969
result = handle(HeapObject::cast(root), local_isolate);
70-
Rehash();
7170
if (is_main_thread()) {
7271
allocator()->RegisterDeserializedObjectsForBlackAllocation();
7372
}
7473
}
74+
75+
Rehash();
7576
CommitPostProcessedObjects();
7677
return scope.CloseAndEscape(result);
7778
}

test/cctest/test-serialize.cc

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3755,7 +3755,7 @@ UNINITIALIZED_TEST(SnapshotCreatorIncludeGlobalProxy) {
37553755
FreeCurrentEmbeddedBlob();
37563756
}
37573757

3758-
UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) {
3758+
UNINITIALIZED_TEST(ReinitializeHashSeedJSCollectionRehashable) {
37593759
DisableAlwaysOpt();
37603760
i::FLAG_rehash_snapshot = true;
37613761
i::FLAG_hash_seed = 42;
@@ -3773,13 +3773,18 @@ UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) {
37733773
CompileRun(
37743774
"var m = new Map();"
37753775
"m.set('a', 1);"
3776-
"m.set('b', 2);");
3776+
"m.set('b', 2);"
3777+
"var s = new Set();"
3778+
"s.add(1);"
3779+
"s.add(globalThis);");
37773780
ExpectInt32("m.get('b')", 2);
3781+
ExpectTrue("s.has(1)");
3782+
ExpectTrue("s.has(globalThis)");
37783783
creator.SetDefaultContext(context);
37793784
}
37803785
blob =
37813786
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
3782-
CHECK(!blob.CanBeRehashed());
3787+
CHECK(blob.CanBeRehashed());
37833788
}
37843789

37853790
i::FLAG_hash_seed = 1337;
@@ -3788,15 +3793,17 @@ UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) {
37883793
create_params.snapshot_blob = &blob;
37893794
v8::Isolate* isolate = v8::Isolate::New(create_params);
37903795
{
3791-
// Check that no rehashing has been performed.
3792-
CHECK_EQ(static_cast<uint64_t>(42),
3796+
// Check that rehashing has been performed.
3797+
CHECK_EQ(static_cast<uint64_t>(1337),
37933798
HashSeed(reinterpret_cast<i::Isolate*>(isolate)));
37943799
v8::Isolate::Scope isolate_scope(isolate);
37953800
v8::HandleScope handle_scope(isolate);
37963801
v8::Local<v8::Context> context = v8::Context::New(isolate);
37973802
CHECK(!context.IsEmpty());
37983803
v8::Context::Scope context_scope(context);
37993804
ExpectInt32("m.get('b')", 2);
3805+
ExpectTrue("s.has(1)");
3806+
ExpectTrue("s.has(globalThis)");
38003807
}
38013808
isolate->Dispose();
38023809
delete[] blob.data;

0 commit comments

Comments
 (0)