Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
deps: V8: cherry-pick 9baf2865671c
Original commit message:

    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

Refs: joyeecheung/v8@9baf286
  • Loading branch information
joyeecheung authored and addaleax committed May 8, 2020
commit 4bc3d2cc7b650385a927de4f7301ef883d62cfbe
2 changes: 1 addition & 1 deletion deps/v8/src/objects/heap-object.h
Original file line number Diff line number Diff line change
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);

// Layout description.
#define HEAP_OBJECT_FIELDS(V) \
Expand Down
2 changes: 2 additions & 0 deletions deps/v8/src/objects/js-collection.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class JSSet : public TorqueGeneratedJSSet<JSSet, JSCollection> {
public:
static void Initialize(Handle<JSSet> set, Isolate* isolate);
static void Clear(Isolate* isolate, Handle<JSSet> set);
void Rehash(Isolate* isolate);

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

// Dispatched behavior.
DECL_PRINTER(JSMap)
Expand Down
38 changes: 34 additions & 4 deletions deps/v8/src/objects/objects.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2285,9 +2285,8 @@ 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;
case ORDERED_HASH_SET_TYPE:
return OrderedHashSet::cast(*this).NumberOfElements() > 0;
return false; // We'll rehash from the JSMap or JSSet referencing them.
case NAME_DICTIONARY_TYPE:
case GLOBAL_DICTIONARY_TYPE:
case NUMBER_DICTIONARY_TYPE:
Expand All @@ -2297,6 +2296,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,10 +2307,13 @@ 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 referencing them.
case ORDERED_NAME_DICTIONARY_TYPE:
// TODO(yangguo): actually support rehashing OrderedHash{Map,Set}.
return false;
case NAME_DICTIONARY_TYPE:
case GLOBAL_DICTIONARY_TYPE:
Expand All @@ -2333,7 +2337,8 @@ bool HeapObject::CanBeRehashed() const {
return false;
}

void HeapObject::RehashBasedOnMap(ReadOnlyRoots roots) {
void HeapObject::RehashBasedOnMap(Isolate* isolate) {
ReadOnlyRoots roots = ReadOnlyRoots(isolate);
switch (map().instance_type()) {
case HASH_TABLE_TYPE:
UNREACHABLE();
Expand Down Expand Up @@ -2365,6 +2370,17 @@ 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 referencing them.
case JS_MAP_TYPE: {
JSMap::cast(*this).Rehash(isolate);
break;
}
case JS_SET_TYPE: {
JSSet::cast(*this).Rehash(isolate);
break;
}
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
DCHECK_EQ(0, SmallOrderedNameDictionary::cast(*this).NumberOfElements());
break;
Expand Down Expand Up @@ -7740,6 +7756,13 @@ void JSSet::Clear(Isolate* isolate, Handle<JSSet> set) {
set->set_table(*table);
}

void JSSet::Rehash(Isolate* isolate) {
Handle<OrderedHashSet> table_handle(OrderedHashSet::cast(table()), isolate);
Handle<OrderedHashSet> new_table =
OrderedHashSet::Rehash(isolate, table_handle).ToHandleChecked();
set_table(*new_table);
}

void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
map->set_table(*table);
Expand All @@ -7751,6 +7774,13 @@ void JSMap::Clear(Isolate* isolate, Handle<JSMap> map) {
map->set_table(*table);
}

void JSMap::Rehash(Isolate* isolate) {
Handle<OrderedHashMap> table_handle(OrderedHashMap::cast(table()), isolate);
Handle<OrderedHashMap> new_table =
OrderedHashMap::Rehash(isolate, table_handle).ToHandleChecked();
set_table(*new_table);
}

void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
Isolate* isolate) {
Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 0);
Expand Down
21 changes: 21 additions & 0 deletions deps/v8/src/objects/ordered-hash-table.cc
Original file line number Diff line number Diff line change
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,20 @@ MaybeHandle<OrderedHashSet> OrderedHashSet::Rehash(Isolate* isolate,
new_capacity);
}

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

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

MaybeHandle<OrderedHashMap> OrderedHashMap::Rehash(Isolate* isolate,
Handle<OrderedHashMap> table,
int new_capacity) {
Expand Down
7 changes: 7 additions & 0 deletions deps/v8/src/objects/ordered-hash-table.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ class OrderedHashTable : public FixedArray {

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

static const int kNotFound = -1;
Expand Down Expand Up @@ -200,6 +201,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 +247,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 +278,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
16 changes: 14 additions & 2 deletions deps/v8/src/snapshot/deserializer.cc
Original file line number Diff line number Diff line change
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_);
}
}

Expand Down Expand Up @@ -130,6 +130,14 @@ 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 (const auto& pair : fillers_to_post_process_) {
DCHECK(!pair.first.IsFiller());
PostProcessNewObject(pair.first, pair.second);
}
}

void Deserializer::LogNewObjectEvents() {
Expand Down Expand Up @@ -201,7 +209,11 @@ HeapObject Deserializer::PostProcessNewObject(HeapObject obj,
DisallowHeapAllocation no_gc;

if ((FLAG_rehash_snapshot && can_rehash_) || deserializing_user_code()) {
if (obj.IsString()) {
if (obj.IsFiller()) {
DCHECK_EQ(fillers_to_post_process_.find(obj),
fillers_to_post_process_.end());
fillers_to_post_process_.insert({obj, space});
} else if (obj.IsString()) {
// Uninitialize hash field as we need to recompute the hash.
String string = String::cast(obj);
string.set_hash_field(String::kEmptyHashField);
Expand Down
5 changes: 5 additions & 0 deletions deps/v8/src/snapshot/deserializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
// TODO(6593): generalize rehashing, and remove this flag.
bool can_rehash_;
std::vector<HeapObject> to_rehash_;
// Store the objects whose maps are deferred and thus initialized as filler
// maps during deserialization, so that they can be processed later when the
// maps become available.
std::unordered_map<HeapObject, SnapshotSpace, Object::Hasher>
fillers_to_post_process_;

#ifdef DEBUG
uint32_t num_api_references_;
Expand Down
3 changes: 2 additions & 1 deletion deps/v8/src/snapshot/object-deserializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ MaybeHandle<HeapObject> ObjectDeserializer::Deserialize(Isolate* isolate) {
LinkAllocationSites();
LogNewMapEvents();
result = handle(HeapObject::cast(root), isolate);
Rehash();
allocator()->RegisterDeserializedObjectsForBlackAllocation();
}

Rehash();
CommitPostProcessedObjects();
return scope.CloseAndEscape(result);
}
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/snapshot/partial-deserializer.cc
Original file line number Diff line number Diff line change
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
14 changes: 9 additions & 5 deletions deps/v8/test/cctest/test-serialize.cc
Original file line number Diff line number Diff line change
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 @@ -3749,15 +3752,16 @@ UNINITIALIZED_TEST(ReinitializeHashSeedNotRehashable) {
create_params.snapshot_blob = &blob;
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
// Check that no rehashing has been performed.
CHECK_EQ(static_cast<uint64_t>(42),
// Check that rehashing has been performed.
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