Skip to content

Commit a2ab135

Browse files
hashseedCommit Bot
authored and
Commit Bot
committed
[snapshot] Rehash strings after deserialization.
See https://goo.gl/6aN8xA Bug: v8:6593 Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng Change-Id: Ic8b0b57195d01d41591397d5d45de3f0f3ebc3d9 Reviewed-on: https://chromium-review.googlesource.com/574527 Reviewed-by: Camillo Bruni <[email protected]> Reviewed-by: Jakob Gruber <[email protected]> Reviewed-by: Ulan Degenbaev <[email protected]> Commit-Queue: Yang Guo <[email protected]> Cr-Commit-Position: refs/heads/master@{#46732}
1 parent 3e19d72 commit a2ab135

20 files changed

+277
-30
lines changed

src/api.cc

+11-2
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,9 @@ StartupData SnapshotCreator::CreateBlob(
666666
isolate->heap()->SetSerializedGlobalProxySizes(*global_proxy_sizes);
667667
}
668668

669+
// We might rehash strings and re-sort descriptors. Clear the lookup cache.
670+
isolate->descriptor_lookup_cache()->Clear();
671+
669672
// If we don't do this then we end up with a stray root pointing at the
670673
// context even after we have disposed of the context.
671674
isolate->heap()->CollectAllAvailableGarbage(
@@ -707,22 +710,28 @@ StartupData SnapshotCreator::CreateBlob(
707710
// Serialize each context with a new partial serializer.
708711
i::List<i::SnapshotData*> context_snapshots(num_additional_contexts + 1);
709712

713+
// TODO(6593): generalize rehashing, and remove this flag.
714+
bool can_be_rehashed = true;
715+
710716
{
711717
// The default snapshot does not support embedder fields.
712718
i::PartialSerializer partial_serializer(
713719
isolate, &startup_serializer, v8::SerializeInternalFieldsCallback());
714720
partial_serializer.Serialize(&default_context, false);
721+
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed();
715722
context_snapshots.Add(new i::SnapshotData(&partial_serializer));
716723
}
717724

718725
for (int i = 0; i < num_additional_contexts; i++) {
719726
i::PartialSerializer partial_serializer(
720727
isolate, &startup_serializer, data->embedder_fields_serializers_[i]);
721728
partial_serializer.Serialize(&contexts[i], true);
729+
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed();
722730
context_snapshots.Add(new i::SnapshotData(&partial_serializer));
723731
}
724732

725733
startup_serializer.SerializeWeakReferencesAndDeferred();
734+
can_be_rehashed = can_be_rehashed && startup_serializer.can_be_rehashed();
726735

727736
#ifdef DEBUG
728737
if (i::FLAG_external_reference_stats) {
@@ -731,8 +740,8 @@ StartupData SnapshotCreator::CreateBlob(
731740
#endif // DEBUG
732741

733742
i::SnapshotData startup_snapshot(&startup_serializer);
734-
StartupData result =
735-
i::Snapshot::CreateSnapshotBlob(&startup_snapshot, &context_snapshots);
743+
StartupData result = i::Snapshot::CreateSnapshotBlob(
744+
&startup_snapshot, &context_snapshots, can_be_rehashed);
736745

737746
// Delete heap-allocated context snapshot instances.
738747
for (const auto& context_snapshot : context_snapshots) {

src/bootstrapper.cc

+2
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,8 @@ Handle<JSFunction> Genesis::GetThrowTypeErrorIntrinsic() {
591591
DCHECK(false);
592592
}
593593

594+
JSObject::MigrateSlowToFast(function, 0, "Bootstrapping");
595+
594596
restricted_properties_thrower_ = function;
595597
return function;
596598
}

src/flag-definitions.h

+2
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,8 @@ DEFINE_BOOL(abort_on_stack_overflow, false,
957957
DEFINE_BOOL(randomize_hashes, true,
958958
"randomize hashes to avoid predictable hash collisions "
959959
"(with snapshots this option cannot override the baked-in seed)")
960+
DEFINE_BOOL(rehash_snapshot, true,
961+
"rehash strings from the snapshot to override the baked-in seed")
960962
DEFINE_INT(hash_seed, 0,
961963
"Fixed seed to use to hash property keys (0 means random)"
962964
"(with snapshots this option cannot override the baked-in seed)")

src/heap/heap.cc

+9-8
Original file line numberDiff line numberDiff line change
@@ -5680,14 +5680,7 @@ bool Heap::SetUp() {
56805680

56815681
// Set up the seed that is used to randomize the string hash function.
56825682
DCHECK(hash_seed() == 0);
5683-
if (FLAG_randomize_hashes) {
5684-
if (FLAG_hash_seed == 0) {
5685-
int rnd = isolate()->random_number_generator()->NextInt();
5686-
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
5687-
} else {
5688-
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
5689-
}
5690-
}
5683+
if (FLAG_randomize_hashes) InitializeHashSeed();
56915684

56925685
for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount);
56935686
i++) {
@@ -5736,6 +5729,14 @@ bool Heap::SetUp() {
57365729
return true;
57375730
}
57385731

5732+
void Heap::InitializeHashSeed() {
5733+
if (FLAG_hash_seed == 0) {
5734+
int rnd = isolate()->random_number_generator()->NextInt();
5735+
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
5736+
} else {
5737+
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
5738+
}
5739+
}
57395740

57405741
bool Heap::CreateHeapObjects() {
57415742
// Create initial maps.

src/heap/heap.h

+3
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,9 @@ class Heap {
935935
// without actually creating any objects.
936936
bool SetUp();
937937

938+
// (Re-)Initialize hash seed from flag or RNG.
939+
void InitializeHashSeed();
940+
938941
// Bootstraps the object heap with the core set of objects required to run.
939942
// Returns whether it succeeded.
940943
bool CreateHeapObjects();

src/js/array.js

+2
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,8 @@ var unscopables = {
13181318
keys: true,
13191319
};
13201320

1321+
%ToFastProperties(unscopables);
1322+
13211323
%AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables,
13221324
DONT_ENUM | READ_ONLY);
13231325

src/objects.cc

+2
Original file line numberDiff line numberDiff line change
@@ -16612,6 +16612,8 @@ BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::Add(
1661216612
Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
1661316613
int*);
1661416614

16615+
template void HashTable<GlobalDictionary, GlobalDictionaryShape>::Rehash();
16616+
1661516617
template Handle<SeededNumberDictionary>
1661616618
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape>::Add(
1661716619
Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,

src/snapshot/deserializer.cc

+39
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ void Deserializer::Deserialize(Isolate* isolate) {
127127
// Needs to be called after the builtins are marked as initialized, in order
128128
// to display the builtin names.
129129
PrintDisassembledCodeObjects();
130+
131+
if (FLAG_rehash_snapshot && can_rehash_) Rehash();
130132
}
131133

132134
MaybeHandle<Object> Deserializer::DeserializePartial(
@@ -157,6 +159,9 @@ MaybeHandle<Object> Deserializer::DeserializePartial(
157159
// changed and logging should be added to notify the profiler et al of the
158160
// new code, which also has to be flushed from instruction cache.
159161
CHECK_EQ(start_address, code_space->top());
162+
163+
if (FLAG_rehash_snapshot && can_rehash_) RehashContext(Context::cast(root));
164+
160165
return Handle<Object>(root, isolate);
161166
}
162167

@@ -183,6 +188,30 @@ MaybeHandle<HeapObject> Deserializer::DeserializeObject(Isolate* isolate) {
183188
}
184189
}
185190

191+
void Deserializer::Rehash() {
192+
DCHECK(can_rehash_);
193+
isolate_->heap()->InitializeHashSeed();
194+
isolate_->heap()->string_table()->Rehash();
195+
isolate_->heap()->weak_object_to_code_table()->Rehash();
196+
SortMapDescriptors();
197+
}
198+
199+
void Deserializer::RehashContext(Context* context) {
200+
DCHECK(can_rehash_);
201+
for (const auto& array : transition_arrays_) array->Sort();
202+
context->global_object()->global_dictionary()->Rehash();
203+
SortMapDescriptors();
204+
}
205+
206+
void Deserializer::SortMapDescriptors() {
207+
for (const auto& address : allocated_maps_) {
208+
Map* map = Map::cast(HeapObject::FromAddress(address));
209+
if (map->instance_descriptors()->number_of_descriptors() > 1) {
210+
map->instance_descriptors()->Sort();
211+
}
212+
}
213+
}
214+
186215
Deserializer::~Deserializer() {
187216
#ifdef DEBUG
188217
// Do not perform checks if we aborted deserialization.
@@ -371,6 +400,16 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
371400
string->resource()));
372401
isolate_->heap()->RegisterExternalString(string);
373402
}
403+
if (FLAG_rehash_snapshot && can_rehash_ && !deserializing_user_code()) {
404+
if (obj->IsString()) {
405+
// Uninitialize hash field as we are going to reinitialize the hash seed.
406+
String* string = String::cast(obj);
407+
string->set_hash_field(String::kEmptyHashField);
408+
} else if (obj->IsTransitionArray() &&
409+
TransitionArray::cast(obj)->number_of_entries() > 1) {
410+
transition_arrays_.Add(TransitionArray::cast(obj));
411+
}
412+
}
374413
// Check alignment.
375414
DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), obj->RequiredAlignment()));
376415
return obj;

src/snapshot/deserializer.h

+17-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ class Deserializer : public SerializerDeserializer {
3939
external_reference_table_(NULL),
4040
deserialized_large_objects_(0),
4141
deserializing_user_code_(deserializing_user_code),
42-
next_alignment_(kWordAligned) {
42+
next_alignment_(kWordAligned),
43+
can_rehash_(false) {
4344
DecodeReservation(data->Reservations());
4445
}
4546

@@ -62,6 +63,8 @@ class Deserializer : public SerializerDeserializer {
6263
attached_objects_.Add(attached_object);
6364
}
6465

66+
void SetRehashability(bool v) { can_rehash_ = v; }
67+
6568
private:
6669
void VisitRootPointers(Root root, Object** start, Object** end) override;
6770

@@ -115,6 +118,15 @@ class Deserializer : public SerializerDeserializer {
115118
// snapshot by chunk index and offset.
116119
HeapObject* GetBackReferencedObject(int space);
117120

121+
// Rehash after deserializing an isolate.
122+
void Rehash();
123+
124+
// Rehash after deserializing a context.
125+
void RehashContext(Context* context);
126+
127+
// Sort descriptors of deserialized maps using new string hashes.
128+
void SortMapDescriptors();
129+
118130
// Cached current isolate.
119131
Isolate* isolate_;
120132

@@ -142,11 +154,15 @@ class Deserializer : public SerializerDeserializer {
142154
List<AccessorInfo*> accessor_infos_;
143155
List<Handle<String> > new_internalized_strings_;
144156
List<Handle<Script> > new_scripts_;
157+
List<TransitionArray*> transition_arrays_;
145158

146159
bool deserializing_user_code_;
147160

148161
AllocationAlignment next_alignment_;
149162

163+
// TODO(6593): generalize rehashing, and remove this flag.
164+
bool can_rehash_;
165+
150166
DISALLOW_COPY_AND_ASSIGN(Deserializer);
151167
};
152168

src/snapshot/partial-serializer.cc

+27-10
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ PartialSerializer::PartialSerializer(
1515
v8::SerializeEmbedderFieldsCallback callback)
1616
: Serializer(isolate),
1717
startup_serializer_(startup_serializer),
18-
serialize_embedder_fields_(callback) {
18+
serialize_embedder_fields_(callback),
19+
rehashable_global_dictionary_(nullptr),
20+
can_be_rehashed_(true) {
1921
InitializeCodeAddressMap();
2022
}
2123

@@ -24,22 +26,26 @@ PartialSerializer::~PartialSerializer() {
2426
}
2527

2628
void PartialSerializer::Serialize(Object** o, bool include_global_proxy) {
27-
if ((*o)->IsContext()) {
29+
if ((*o)->IsNativeContext()) {
2830
Context* context = Context::cast(*o);
2931
reference_map()->AddAttachedReference(context->global_proxy());
3032
// The bootstrap snapshot has a code-stub context. When serializing the
3133
// partial snapshot, it is chained into the weak context list on the isolate
3234
// and it's next context pointer may point to the code-stub context. Clear
3335
// it before serializing, it will get re-added to the context list
3436
// explicitly when it's loaded.
35-
if (context->IsNativeContext()) {
36-
context->set(Context::NEXT_CONTEXT_LINK,
37-
isolate_->heap()->undefined_value());
38-
DCHECK(!context->global_object()->IsUndefined(context->GetIsolate()));
39-
// Reset math random cache to get fresh random numbers.
40-
context->set_math_random_index(Smi::kZero);
41-
context->set_math_random_cache(isolate_->heap()->undefined_value());
42-
}
37+
context->set(Context::NEXT_CONTEXT_LINK,
38+
isolate_->heap()->undefined_value());
39+
DCHECK(!context->global_object()->IsUndefined(context->GetIsolate()));
40+
// Reset math random cache to get fresh random numbers.
41+
context->set_math_random_index(Smi::kZero);
42+
context->set_math_random_cache(isolate_->heap()->undefined_value());
43+
DCHECK_NULL(rehashable_global_dictionary_);
44+
rehashable_global_dictionary_ =
45+
context->global_object()->global_dictionary();
46+
} else {
47+
// We only do rehashing for native contexts.
48+
can_be_rehashed_ = false;
4349
}
4450
VisitRootPointer(Root::kPartialSnapshotCache, o);
4551
SerializeDeferredObjects();
@@ -104,6 +110,8 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
104110
}
105111
}
106112

113+
if (obj->IsHashTable()) CheckRehashability(obj);
114+
107115
// Object has not yet been serialized. Serialize it here.
108116
ObjectSerializer serializer(this, obj, &sink_, how_to_code, where_to_point);
109117
serializer.Serialize();
@@ -152,5 +160,14 @@ void PartialSerializer::SerializeEmbedderFields() {
152160
sink_.Put(kSynchronize, "Finished with embedder fields data");
153161
}
154162

163+
void PartialSerializer::CheckRehashability(HeapObject* table) {
164+
DCHECK(table->IsHashTable());
165+
if (!can_be_rehashed_) return;
166+
// We can only correctly rehash if the global dictionary is the only hash
167+
// table that we deserialize.
168+
if (table == rehashable_global_dictionary_) return;
169+
can_be_rehashed_ = false;
170+
}
171+
155172
} // namespace internal
156173
} // namespace v8

src/snapshot/partial-serializer.h

+8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class PartialSerializer : public Serializer {
2323
// Serialize the objects reachable from a single object pointer.
2424
void Serialize(Object** o, bool include_global_proxy);
2525

26+
bool can_be_rehashed() const { return can_be_rehashed_; }
27+
2628
private:
2729
void SerializeObject(HeapObject* o, HowToCode how_to_code,
2830
WhereToPoint where_to_point, int skip) override;
@@ -31,9 +33,15 @@ class PartialSerializer : public Serializer {
3133

3234
void SerializeEmbedderFields();
3335

36+
void CheckRehashability(HeapObject* table);
37+
3438
StartupSerializer* startup_serializer_;
3539
List<JSObject*> embedder_field_holders_;
3640
v8::SerializeEmbedderFieldsCallback serialize_embedder_fields_;
41+
GlobalDictionary* rehashable_global_dictionary_;
42+
// Indicates whether we only serialized hash tables that we can rehash.
43+
// TODO(yangguo): generalize rehashing, and remove this flag.
44+
bool can_be_rehashed_;
3745
DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
3846
};
3947

src/snapshot/snapshot-common.cc

+12-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ bool Snapshot::Initialize(Isolate* isolate) {
4141
Vector<const byte> startup_data = ExtractStartupData(blob);
4242
SnapshotData snapshot_data(startup_data);
4343
Deserializer deserializer(&snapshot_data);
44+
deserializer.SetRehashability(ExtractRehashability(blob));
4445
bool success = isolate->Init(&deserializer);
4546
if (FLAG_profile_deserialization) {
4647
double ms = timer.Elapsed().InMillisecondsF();
@@ -62,6 +63,7 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
6263
ExtractContextData(blob, static_cast<int>(context_index));
6364
SnapshotData snapshot_data(context_data);
6465
Deserializer deserializer(&snapshot_data);
66+
deserializer.SetRehashability(ExtractRehashability(blob));
6567

6668
MaybeHandle<Object> maybe_context = deserializer.DeserializePartial(
6769
isolate, global_proxy, embedder_fields_deserializer);
@@ -98,7 +100,7 @@ void ProfileDeserialization(const SnapshotData* startup_snapshot,
98100

99101
v8::StartupData Snapshot::CreateSnapshotBlob(
100102
const SnapshotData* startup_snapshot,
101-
const List<SnapshotData*>* context_snapshots) {
103+
const List<SnapshotData*>* context_snapshots, bool can_be_rehashed) {
102104
int num_contexts = context_snapshots->length();
103105
int startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
104106
int total_length = startup_snapshot_offset;
@@ -111,6 +113,8 @@ v8::StartupData Snapshot::CreateSnapshotBlob(
111113

112114
char* data = new char[total_length];
113115
memcpy(data + kNumberOfContextsOffset, &num_contexts, kInt32Size);
116+
int rehashability = can_be_rehashed ? 1 : 0;
117+
memcpy(data + kRehashabilityOffset, &rehashability, kInt32Size);
114118
int payload_offset = StartupSnapshotOffset(num_contexts);
115119
int payload_length = startup_snapshot->RawData().length();
116120
memcpy(data + payload_offset, startup_snapshot->RawData().start(),
@@ -143,6 +147,13 @@ int Snapshot::ExtractNumContexts(const v8::StartupData* data) {
143147
return num_contexts;
144148
}
145149

150+
bool Snapshot::ExtractRehashability(const v8::StartupData* data) {
151+
CHECK_LT(kRehashabilityOffset, data->raw_size);
152+
int rehashability;
153+
memcpy(&rehashability, data->data + kRehashabilityOffset, kInt32Size);
154+
return rehashability != 0;
155+
}
156+
146157
Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
147158
int num_contexts = ExtractNumContexts(data);
148159
int startup_offset = StartupSnapshotOffset(num_contexts);

0 commit comments

Comments
 (0)