Skip to content

Commit

Permalink
[snapshot] rehash JSMap and JSSet during deserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
joyeecheung committed May 5, 2020
1 parent 6700ce8 commit 3d52c32
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 10 deletions.
2 changes: 1 addition & 1 deletion deps/v8/src/objects/heap-object.h
Expand Up @@ -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) \
Expand Down
31 changes: 28 additions & 3 deletions deps/v8/src/objects/objects.cc
Expand Up @@ -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:
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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<OrderedHashMap> table(OrderedHashMap::cast(map.table()), isolate);
Handle<OrderedHashMap> new_table =
OrderedHashMap::Rehash(isolate, table).ToHandleChecked();
map.set_table(*new_table);
break;
}
case JS_SET_TYPE: {
JSSet set = JSSet::cast(*this);
Handle<OrderedHashSet> table(OrderedHashSet::cast(set.table()), isolate);
Handle<OrderedHashSet> 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;
Expand Down
17 changes: 17 additions & 0 deletions deps/v8/src/objects/ordered-hash-table.cc
Expand Up @@ -193,6 +193,13 @@ HeapObject OrderedHashMap::GetEmpty(ReadOnlyRoots ro_roots) {
return ro_roots.empty_ordered_hash_map();
}

template <class Derived, int entrysize>
MaybeHandle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
Isolate* isolate, Handle<Derived> table) {
return OrderedHashTable<Derived, entrysize>::Rehash(isolate, table,
table->Capacity());
}

template <class Derived, int entrysize>
MaybeHandle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
Isolate* isolate, Handle<Derived> table, int new_capacity) {
Expand Down Expand Up @@ -249,6 +256,16 @@ MaybeHandle<OrderedHashSet> OrderedHashSet::Rehash(Isolate* isolate,
new_capacity);
}

MaybeHandle<OrderedHashSet> OrderedHashSet::Rehash(
Isolate* isolate, Handle<OrderedHashSet> table) {
return OrderedHashTable<OrderedHashSet, 1>::Rehash(isolate, table);
}

MaybeHandle<OrderedHashMap> OrderedHashMap::Rehash(
Isolate* isolate, Handle<OrderedHashMap> table) {
return OrderedHashTable<OrderedHashMap, 2>::Rehash(isolate, table);
}

MaybeHandle<OrderedHashMap> OrderedHashMap::Rehash(Isolate* isolate,
Handle<OrderedHashMap> table,
int new_capacity) {
Expand Down
6 changes: 6 additions & 0 deletions deps/v8/src/objects/ordered-hash-table.h
Expand Up @@ -200,6 +200,8 @@ class OrderedHashTable : public FixedArray {
static MaybeHandle<Derived> Allocate(
Isolate* isolate, int capacity,
AllocationType allocation = AllocationType::kYoung);

static MaybeHandle<Derived> Rehash(Isolate* isolate, Handle<Derived> table);
static MaybeHandle<Derived> Rehash(Isolate* isolate, Handle<Derived> table,
int new_capacity);

Expand Down Expand Up @@ -244,6 +246,8 @@ class V8_EXPORT_PRIVATE OrderedHashSet
static MaybeHandle<OrderedHashSet> Rehash(Isolate* isolate,
Handle<OrderedHashSet> table,
int new_capacity);
static MaybeHandle<OrderedHashSet> Rehash(Isolate* isolate,
Handle<OrderedHashSet> table);
static MaybeHandle<OrderedHashSet> Allocate(
Isolate* isolate, int capacity,
AllocationType allocation = AllocationType::kYoung);
Expand Down Expand Up @@ -273,6 +277,8 @@ class V8_EXPORT_PRIVATE OrderedHashMap
static MaybeHandle<OrderedHashMap> Rehash(Isolate* isolate,
Handle<OrderedHashMap> table,
int new_capacity);
static MaybeHandle<OrderedHashMap> Rehash(Isolate* isolate,
Handle<OrderedHashMap> table);
Object ValueAt(int entry);

// This takes and returns raw Address values containing tagged Object
Expand Down
14 changes: 13 additions & 1 deletion deps/v8/src/snapshot/deserializer.cc
Expand Up @@ -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_));
}
}

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions deps/v8/src/snapshot/deserializer.h
Expand Up @@ -194,6 +194,8 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
// TODO(6593): generalize rehashing, and remove this flag.
bool can_rehash_;
std::vector<HeapObject> to_rehash_;
std::unordered_map<HeapObject, SnapshotSpace, Object::Hasher>
fillers_to_post_process_;

#ifdef DEBUG
uint32_t num_api_references_;
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/snapshot/partial-deserializer.cc
Expand Up @@ -57,12 +57,12 @@ MaybeHandle<Object> 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;
Expand Down
12 changes: 8 additions & 4 deletions deps/v8/test/cctest/test-serialize.cc
Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -3750,14 +3753,15 @@ UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) {
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
// Check that no rehashing has been performed.
CHECK_EQ(static_cast<uint64_t>(42),
CHECK_EQ(static_cast<uint64_t>(1337),
HashSeed(reinterpret_cast<i::Isolate*>(isolate)));
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
ExpectInt32("m.get('b')", 2);
ExpectTrue("s.has(1)");
}
isolate->Dispose();
delete[] blob.data;
Expand Down

0 comments on commit 3d52c32

Please sign in to comment.