Skip to content

Commit 8dce05f

Browse files
hashseedaddaleax
authored andcommitted
deps: backport rehash strings after deserialization
Original commit messages: v8/v8@a2ab135 [snapshot] Rehash strings after deserialization. See https://goo.gl/6aN8xA Bug: v8:6593 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} v8/v8@182caaf Do not track transitions for built-in objects. Objects created during bootstrapping do not need a transition tree except for elements kind transitions. Bug: v8:6596 Change-Id: I237b8b2792f201336e1c9731c815095dd06bc182 Reviewed-on: https://chromium-review.googlesource.com/571750 Reviewed-by: Igor Sheludko <[email protected]> Commit-Queue: Yang Guo <[email protected]> Cr-Commit-Position: refs/heads/master@{#46693} Fixes: #14171 PR-URL: #14345 Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Ali Ijaz Sheikh <[email protected]>
1 parent 9623ce5 commit 8dce05f

23 files changed

+327
-37
lines changed

configure

+4-4
Original file line numberDiff line numberDiff line change
@@ -425,12 +425,12 @@ parser.add_option('--without-perfctr',
425425
# Dummy option for backwards compatibility
426426
parser.add_option('--with-snapshot',
427427
action='store_true',
428-
dest='with_snapshot',
428+
dest='unused_with_snapshot',
429429
help=optparse.SUPPRESS_HELP)
430430

431431
parser.add_option('--without-snapshot',
432432
action='store_true',
433-
dest='unused_without_snapshot',
433+
dest='without_snapshot',
434434
help=optparse.SUPPRESS_HELP)
435435

436436
parser.add_option('--without-ssl',
@@ -815,7 +815,7 @@ def configure_node(o):
815815
cross_compiling = (options.cross_compiling
816816
if options.cross_compiling is not None
817817
else target_arch != host_arch)
818-
want_snapshots = 1 if options.with_snapshot else 0
818+
want_snapshots = not options.without_snapshot
819819
o['variables']['want_separate_host_toolset'] = int(
820820
cross_compiling and want_snapshots)
821821
o['variables']['want_separate_host_toolset_mkpeephole'] = int(
@@ -962,7 +962,7 @@ def configure_v8(o):
962962
o['variables']['v8_optimized_debug'] = 0 # Compile with -O0 in debug builds.
963963
o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables.
964964
o['variables']['v8_promise_internal_field_count'] = 1 # Add internal field to promises for async hooks.
965-
o['variables']['v8_use_snapshot'] = b(options.with_snapshot)
965+
o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true'
966966
o['variables']['v8_trace_maps'] = 1 if options.trace_maps else 0
967967
o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform)
968968
o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8)

deps/v8/include/v8-version.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#define V8_MAJOR_VERSION 5
1212
#define V8_MINOR_VERSION 9
1313
#define V8_BUILD_NUMBER 211
14-
#define V8_PATCH_LEVEL 38
14+
#define V8_PATCH_LEVEL 39
1515

1616
// Use 1 for candidates and 0 otherwise.
1717
// (Boolean macro values are not supported by all preprocessors.)

deps/v8/src/api.cc

+11-2
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,9 @@ StartupData SnapshotCreator::CreateBlob(
601601
isolate->heap()->SetSerializedGlobalProxySizes(*global_proxy_sizes);
602602
}
603603

604+
// We might rehash strings and re-sort descriptors. Clear the lookup cache.
605+
isolate->descriptor_lookup_cache()->Clear();
606+
604607
// If we don't do this then we end up with a stray root pointing at the
605608
// context even after we have disposed of the context.
606609
isolate->heap()->CollectAllAvailableGarbage(
@@ -642,22 +645,28 @@ StartupData SnapshotCreator::CreateBlob(
642645
// Serialize each context with a new partial serializer.
643646
i::List<i::SnapshotData*> context_snapshots(num_additional_contexts + 1);
644647

648+
// TODO(6593): generalize rehashing, and remove this flag.
649+
bool can_be_rehashed = true;
650+
645651
{
646652
// The default snapshot does not support embedder fields.
647653
i::PartialSerializer partial_serializer(
648654
isolate, &startup_serializer, v8::SerializeInternalFieldsCallback());
649655
partial_serializer.Serialize(&default_context, false);
656+
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed();
650657
context_snapshots.Add(new i::SnapshotData(&partial_serializer));
651658
}
652659

653660
for (int i = 0; i < num_additional_contexts; i++) {
654661
i::PartialSerializer partial_serializer(
655662
isolate, &startup_serializer, data->embedder_fields_serializers_[i]);
656663
partial_serializer.Serialize(&contexts[i], true);
664+
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed();
657665
context_snapshots.Add(new i::SnapshotData(&partial_serializer));
658666
}
659667

660668
startup_serializer.SerializeWeakReferencesAndDeferred();
669+
can_be_rehashed = can_be_rehashed && startup_serializer.can_be_rehashed();
661670

662671
#ifdef DEBUG
663672
if (i::FLAG_external_reference_stats) {
@@ -666,8 +675,8 @@ StartupData SnapshotCreator::CreateBlob(
666675
#endif // DEBUG
667676

668677
i::SnapshotData startup_snapshot(&startup_serializer);
669-
StartupData result =
670-
i::Snapshot::CreateSnapshotBlob(&startup_snapshot, &context_snapshots);
678+
StartupData result = i::Snapshot::CreateSnapshotBlob(
679+
&startup_snapshot, &context_snapshots, can_be_rehashed);
671680

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

deps/v8/src/bootstrapper.cc

+6
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,8 @@ Handle<JSFunction> Genesis::GetThrowTypeErrorIntrinsic(
644644
DCHECK(false);
645645
}
646646

647+
JSObject::MigrateSlowToFast(function, 0, "Bootstrapping");
648+
647649
return function;
648650
}
649651

@@ -1385,6 +1387,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
13851387
sloppy_function_map_writable_prototype_->SetConstructor(*function_fun);
13861388
strict_function_map_writable_prototype_->SetConstructor(*function_fun);
13871389
class_function_map_->SetConstructor(*function_fun);
1390+
1391+
JSObject::MigrateSlowToFast(function_fun, 0, "Bootstrapping");
13881392
}
13891393

13901394
{
@@ -2204,6 +2208,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
22042208
info->set_length(1);
22052209
native_context()->set_promise_reject_shared_fun(*info);
22062210
}
2211+
2212+
JSObject::MigrateSlowToFast(promise_fun, 0, "Bootstrapping");
22072213
}
22082214

22092215
{ // -- R e g E x p

deps/v8/src/flag-definitions.h

+2
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,8 @@ DEFINE_BOOL(abort_on_stack_overflow, false,
987987
DEFINE_BOOL(randomize_hashes, true,
988988
"randomize hashes to avoid predictable hash collisions "
989989
"(with snapshots this option cannot override the baked-in seed)")
990+
DEFINE_BOOL(rehash_snapshot, true,
991+
"rehash strings from the snapshot to override the baked-in seed")
990992
DEFINE_INT(hash_seed, 0,
991993
"Fixed seed to use to hash property keys (0 means random)"
992994
"(with snapshots this option cannot override the baked-in seed)")

deps/v8/src/heap/heap.cc

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

55475547
// Set up the seed that is used to randomize the string hash function.
55485548
DCHECK(hash_seed() == 0);
5549-
if (FLAG_randomize_hashes) {
5550-
if (FLAG_hash_seed == 0) {
5551-
int rnd = isolate()->random_number_generator()->NextInt();
5552-
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
5553-
} else {
5554-
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
5555-
}
5556-
}
5549+
if (FLAG_randomize_hashes) InitializeHashSeed();
55575550

55585551
for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount);
55595552
i++) {
@@ -5591,6 +5584,14 @@ bool Heap::SetUp() {
55915584
return true;
55925585
}
55935586

5587+
void Heap::InitializeHashSeed() {
5588+
if (FLAG_hash_seed == 0) {
5589+
int rnd = isolate()->random_number_generator()->NextInt();
5590+
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
5591+
} else {
5592+
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
5593+
}
5594+
}
55945595

55955596
bool Heap::CreateHeapObjects() {
55965597
// Create initial maps.

deps/v8/src/heap/heap.h

+3
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,9 @@ class Heap {
994994
// without actually creating any objects.
995995
bool SetUp();
996996

997+
// (Re-)Initialize hash seed from flag or RNG.
998+
void InitializeHashSeed();
999+
9971000
// Bootstraps the object heap with the core set of objects required to run.
9981001
// Returns whether it succeeded.
9991002
bool CreateHeapObjects();

deps/v8/src/js/array.js

+2
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,8 @@ var unscopables = {
13341334
keys: true,
13351335
};
13361336

1337+
%ToFastProperties(unscopables);
1338+
13371339
%AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables,
13381340
DONT_ENUM | READ_ONLY);
13391341

deps/v8/src/objects.cc

+10-1
Original file line numberDiff line numberDiff line change
@@ -8823,7 +8823,13 @@ void Map::TraceAllTransitions(Map* map) {
88238823

88248824
void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
88258825
Handle<Name> name, SimpleTransitionFlag flag) {
8826-
if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) {
8826+
Isolate* isolate = parent->GetIsolate();
8827+
// Do not track transitions during bootstrap except for element transitions.
8828+
if (isolate->bootstrapper()->IsActive() &&
8829+
!name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
8830+
return;
8831+
}
8832+
if (!parent->GetBackPointer()->IsUndefined(isolate)) {
88278833
parent->set_owns_descriptors(false);
88288834
} else {
88298835
// |parent| is initial map and it must keep the ownership, there must be no
@@ -16779,6 +16785,9 @@ template class Dictionary<UnseededNumberDictionary,
1677916785
UnseededNumberDictionaryShape,
1678016786
uint32_t>;
1678116787

16788+
template void
16789+
HashTable<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Rehash(Handle<Name> key);
16790+
1678216791
template Handle<SeededNumberDictionary>
1678316792
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
1678416793
Isolate*, int at_least_space_for, PretenureFlag pretenure,

deps/v8/src/snapshot/deserializer.cc

+72
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ void Deserializer::Deserialize(Isolate* isolate) {
121121
LOG_CODE_EVENT(isolate_, LogCodeObjects());
122122
LOG_CODE_EVENT(isolate_, LogBytecodeHandlers());
123123
LOG_CODE_EVENT(isolate_, LogCompiledFunctions());
124+
125+
if (FLAG_rehash_snapshot && can_rehash_) Rehash();
124126
}
125127

126128
MaybeHandle<Object> Deserializer::DeserializePartial(
@@ -151,6 +153,9 @@ MaybeHandle<Object> Deserializer::DeserializePartial(
151153
// changed and logging should be added to notify the profiler et al of the
152154
// new code, which also has to be flushed from instruction cache.
153155
CHECK_EQ(start_address, code_space->top());
156+
157+
if (FLAG_rehash_snapshot && can_rehash_) RehashContext(Context::cast(root));
158+
154159
return Handle<Object>(root, isolate);
155160
}
156161

@@ -177,6 +182,63 @@ MaybeHandle<HeapObject> Deserializer::DeserializeObject(Isolate* isolate) {
177182
}
178183
}
179184

185+
// We only really just need HashForObject here.
186+
class StringRehashKey : public HashTableKey {
187+
public:
188+
uint32_t HashForObject(Object* other) override {
189+
return String::cast(other)->Hash();
190+
}
191+
192+
static uint32_t StringHash(Object* obj) {
193+
UNREACHABLE();
194+
return String::cast(obj)->Hash();
195+
}
196+
197+
bool IsMatch(Object* string) override {
198+
UNREACHABLE();
199+
return false;
200+
}
201+
202+
uint32_t Hash() override {
203+
UNREACHABLE();
204+
return 0;
205+
}
206+
207+
Handle<Object> AsHandle(Isolate* isolate) override {
208+
UNREACHABLE();
209+
return isolate->factory()->empty_string();
210+
}
211+
};
212+
213+
void Deserializer::Rehash() {
214+
DCHECK(can_rehash_);
215+
isolate_->heap()->InitializeHashSeed();
216+
if (FLAG_profile_deserialization) {
217+
PrintF("Re-initializing hash seed to %x\n",
218+
isolate_->heap()->hash_seed()->value());
219+
}
220+
StringRehashKey string_rehash_key;
221+
isolate_->heap()->string_table()->Rehash(&string_rehash_key);
222+
SortMapDescriptors();
223+
}
224+
225+
void Deserializer::RehashContext(Context* context) {
226+
DCHECK(can_rehash_);
227+
for (const auto& array : transition_arrays_) array->Sort();
228+
Handle<Name> dummy = isolate_->factory()->empty_string();
229+
context->global_object()->global_dictionary()->Rehash(dummy);
230+
SortMapDescriptors();
231+
}
232+
233+
void Deserializer::SortMapDescriptors() {
234+
for (const auto& address : allocated_maps_) {
235+
Map* map = Map::cast(HeapObject::FromAddress(address));
236+
if (map->instance_descriptors()->number_of_descriptors() > 1) {
237+
map->instance_descriptors()->Sort();
238+
}
239+
}
240+
}
241+
180242
Deserializer::~Deserializer() {
181243
#ifdef DEBUG
182244
// Do not perform checks if we aborted deserialization.
@@ -367,6 +429,16 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
367429
string->resource()));
368430
isolate_->heap()->RegisterExternalString(string);
369431
}
432+
if (FLAG_rehash_snapshot && can_rehash_ && !deserializing_user_code()) {
433+
if (obj->IsString()) {
434+
// Uninitialize hash field as we are going to reinitialize the hash seed.
435+
String* string = String::cast(obj);
436+
string->set_hash_field(String::kEmptyHashField);
437+
} else if (obj->IsTransitionArray() &&
438+
TransitionArray::cast(obj)->number_of_entries() > 1) {
439+
transition_arrays_.Add(TransitionArray::cast(obj));
440+
}
441+
}
370442
// Check alignment.
371443
DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), obj->RequiredAlignment()));
372444
return obj;

deps/v8/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 VisitPointers(Object** start, Object** end) override;
6770

@@ -117,6 +120,15 @@ class Deserializer : public SerializerDeserializer {
117120
// snapshot by chunk index and offset.
118121
HeapObject* GetBackReferencedObject(int space);
119122

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

@@ -144,11 +156,15 @@ class Deserializer : public SerializerDeserializer {
144156
List<AccessorInfo*> accessor_infos_;
145157
List<Handle<String> > new_internalized_strings_;
146158
List<Handle<Script> > new_scripts_;
159+
List<TransitionArray*> transition_arrays_;
147160

148161
bool deserializing_user_code_;
149162

150163
AllocationAlignment next_alignment_;
151164

165+
// TODO(6593): generalize rehashing, and remove this flag.
166+
bool can_rehash_;
167+
152168
DISALLOW_COPY_AND_ASSIGN(Deserializer);
153169
};
154170

0 commit comments

Comments
 (0)