Skip to content

Commit 67ce52c

Browse files
hashseedMylesBorins
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: #14385
1 parent 5900ebe commit 67ce52c

22 files changed

+302
-25
lines changed

configure

+4-4
Original file line numberDiff line numberDiff line change
@@ -419,12 +419,12 @@ parser.add_option('--without-perfctr',
419419
# Dummy option for backwards compatibility
420420
parser.add_option('--with-snapshot',
421421
action='store_true',
422-
dest='with_snapshot',
422+
dest='unused_with_snapshot',
423423
help=optparse.SUPPRESS_HELP)
424424

425425
parser.add_option('--without-snapshot',
426426
action='store_true',
427-
dest='unused_without_snapshot',
427+
dest='without_snapshot',
428428
help=optparse.SUPPRESS_HELP)
429429

430430
parser.add_option('--without-ssl',
@@ -802,7 +802,7 @@ def configure_node(o):
802802
cross_compiling = (options.cross_compiling
803803
if options.cross_compiling is not None
804804
else target_arch != host_arch)
805-
want_snapshots = 1 if options.with_snapshot else 0
805+
want_snapshots = not options.without_snapshot
806806
o['variables']['want_separate_host_toolset'] = int(
807807
cross_compiling and want_snapshots)
808808

@@ -946,7 +946,7 @@ def configure_v8(o):
946946
o['variables']['v8_no_strict_aliasing'] = 1 # Work around compiler bugs.
947947
o['variables']['v8_optimized_debug'] = 0 # Compile with -O0 in debug builds.
948948
o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables.
949-
o['variables']['v8_use_snapshot'] = b(options.with_snapshot)
949+
o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true'
950950
o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform)
951951
o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8)
952952
o['variables']['force_dynamic_crt'] = 1 if options.shared else 0

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 1
1313
#define V8_BUILD_NUMBER 281
14-
#define V8_PATCH_LEVEL 103
14+
#define V8_PATCH_LEVEL 104
1515

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

deps/v8/src/api.cc

+6
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ StartupData SerializeIsolateAndContext(
391391

392392
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
393393

394+
// We might rehash strings and re-sort descriptors. Clear the lookup cache.
395+
internal_isolate->descriptor_lookup_cache()->Clear();
396+
394397
// If we don't do this then we end up with a stray root pointing at the
395398
// context even after we have disposed of the context.
396399
internal_isolate->heap()->CollectAllAvailableGarbage("mksnapshot");
@@ -428,6 +431,9 @@ StartupData SerializeIsolateAndContext(
428431
context_ser.Serialize(&raw_context);
429432
ser.SerializeWeakReferencesAndDeferred();
430433

434+
metadata.set_can_rehash(ser.can_be_rehashed() &&
435+
context_ser.can_be_rehashed());
436+
431437
return i::Snapshot::CreateSnapshotBlob(ser, context_ser, metadata);
432438
}
433439

deps/v8/src/bootstrapper.cc

+4
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,8 @@ Handle<JSFunction> Genesis::GetThrowTypeErrorIntrinsic(
655655
DCHECK(false);
656656
}
657657

658+
JSObject::MigrateSlowToFast(function, 0, "Bootstrapping");
659+
658660
return function;
659661
}
660662

@@ -1133,6 +1135,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
11331135

11341136
sloppy_function_map_writable_prototype_->SetConstructor(*function_fun);
11351137
strict_function_map_writable_prototype_->SetConstructor(*function_fun);
1138+
1139+
JSObject::MigrateSlowToFast(function_fun, 0, "Bootstrapping");
11361140
}
11371141

11381142
{ // --- A r r a y ---

deps/v8/src/flag-definitions.h

+2
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,8 @@ DEFINE_BOOL(abort_on_uncaught_exception, false,
830830
DEFINE_BOOL(randomize_hashes, true,
831831
"randomize hashes to avoid predictable hash collisions "
832832
"(with snapshots this option cannot override the baked-in seed)")
833+
DEFINE_BOOL(rehash_snapshot, true,
834+
"rehash strings from the snapshot to override the baked-in seed")
833835
DEFINE_INT(hash_seed, 0,
834836
"Fixed seed to use to hash property keys (0 means random)"
835837
"(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
@@ -5348,14 +5348,7 @@ bool Heap::SetUp() {
53485348

53495349
// Set up the seed that is used to randomize the string hash function.
53505350
DCHECK(hash_seed() == 0);
5351-
if (FLAG_randomize_hashes) {
5352-
if (FLAG_hash_seed == 0) {
5353-
int rnd = isolate()->random_number_generator()->NextInt();
5354-
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
5355-
} else {
5356-
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
5357-
}
5358-
}
5351+
if (FLAG_randomize_hashes) InitializeHashSeed();
53595352

53605353
for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount);
53615354
i++) {
@@ -5393,6 +5386,14 @@ bool Heap::SetUp() {
53935386
return true;
53945387
}
53955388

5389+
void Heap::InitializeHashSeed() {
5390+
if (FLAG_hash_seed == 0) {
5391+
int rnd = isolate()->random_number_generator()->NextInt();
5392+
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
5393+
} else {
5394+
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
5395+
}
5396+
}
53965397

53975398
bool Heap::CreateHeapObjects() {
53985399
// Create initial maps.

deps/v8/src/heap/heap.h

+3
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,9 @@ class Heap {
864864
// without actually creating any objects.
865865
bool SetUp();
866866

867+
// (Re-)Initialize hash seed from flag or RNG.
868+
void InitializeHashSeed();
869+
867870
// Bootstraps the object heap with the core set of objects required to run.
868871
// Returns whether it succeeded.
869872
bool CreateHeapObjects();

deps/v8/src/js/array.js

+2
Original file line numberDiff line numberDiff line change
@@ -1831,6 +1831,8 @@ var unscopables = {
18311831
keys: true,
18321832
};
18331833

1834+
%ToFastProperties(unscopables);
1835+
18341836
%AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables,
18351837
DONT_ENUM | READ_ONLY);
18361838

deps/v8/src/objects.cc

+12
Original file line numberDiff line numberDiff line change
@@ -9469,6 +9469,12 @@ void Map::TraceAllTransitions(Map* map) {
94699469

94709470
void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
94719471
Handle<Name> name, SimpleTransitionFlag flag) {
9472+
// Do not track transitions during bootstrap except for element transitions.
9473+
Isolate* isolate = parent->GetIsolate();
9474+
if (isolate->bootstrapper()->IsActive() &&
9475+
!name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
9476+
return;
9477+
}
94729478
if (!parent->GetBackPointer()->IsUndefined()) {
94739479
parent->set_owns_descriptors(false);
94749480
} else {
@@ -17520,6 +17526,12 @@ template class Dictionary<UnseededNumberDictionary,
1752017526
UnseededNumberDictionaryShape,
1752117527
uint32_t>;
1752217528

17529+
template void
17530+
HashTable<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Rehash(Handle<Name> key);
17531+
17532+
template void
17533+
HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::Rehash(Handle<Name> key);
17534+
1752317535
template Handle<SeededNumberDictionary>
1752417536
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
1752517537
New(Isolate*, int at_least_space_for, PretenureFlag pretenure);

deps/v8/src/snapshot/deserializer.cc

+75
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ void Deserializer::Deserialize(Isolate* isolate) {
109109
LOG_CODE_EVENT(isolate_, LogCodeObjects());
110110
LOG_CODE_EVENT(isolate_, LogBytecodeHandlers());
111111
LOG_CODE_EVENT(isolate_, LogCompiledFunctions());
112+
113+
if (FLAG_rehash_snapshot && can_rehash_) Rehash();
112114
}
113115

114116
MaybeHandle<Object> Deserializer::DeserializePartial(
@@ -138,6 +140,9 @@ MaybeHandle<Object> Deserializer::DeserializePartial(
138140
// changed and logging should be added to notify the profiler et al of the
139141
// new code, which also has to be flushed from instruction cache.
140142
CHECK_EQ(start_address, code_space->top());
143+
144+
if (FLAG_rehash_snapshot && can_rehash_) RehashContext(Context::cast(root));
145+
141146
return Handle<Object>(root, isolate);
142147
}
143148

@@ -164,6 +169,64 @@ MaybeHandle<SharedFunctionInfo> Deserializer::DeserializeCode(
164169
}
165170
}
166171

172+
// We only really just need HashForObject here.
173+
class StringRehashKey : public HashTableKey {
174+
public:
175+
uint32_t HashForObject(Object* other) override {
176+
return String::cast(other)->Hash();
177+
}
178+
179+
static uint32_t StringHash(Object* obj) {
180+
UNREACHABLE();
181+
return String::cast(obj)->Hash();
182+
}
183+
184+
bool IsMatch(Object* string) override {
185+
UNREACHABLE();
186+
return false;
187+
}
188+
189+
uint32_t Hash() override {
190+
UNREACHABLE();
191+
return 0;
192+
}
193+
194+
Handle<Object> AsHandle(Isolate* isolate) override {
195+
UNREACHABLE();
196+
return isolate->factory()->empty_string();
197+
}
198+
};
199+
200+
void Deserializer::Rehash() {
201+
DCHECK(can_rehash_);
202+
isolate_->heap()->InitializeHashSeed();
203+
if (FLAG_profile_deserialization) {
204+
PrintF("Re-initializing hash seed to %x\n",
205+
isolate_->heap()->hash_seed()->value());
206+
}
207+
StringRehashKey string_rehash_key;
208+
isolate_->heap()->string_table()->Rehash(&string_rehash_key);
209+
isolate_->heap()->intrinsic_function_names()->Rehash(
210+
isolate_->factory()->empty_string());
211+
SortMapDescriptors();
212+
}
213+
214+
void Deserializer::RehashContext(Context* context) {
215+
DCHECK(can_rehash_);
216+
for (const auto& array : transition_arrays_) array->Sort();
217+
Handle<Name> dummy = isolate_->factory()->empty_string();
218+
context->global_object()->global_dictionary()->Rehash(dummy);
219+
SortMapDescriptors();
220+
}
221+
222+
void Deserializer::SortMapDescriptors() {
223+
for (const auto& map : maps_) {
224+
if (map->instance_descriptors()->number_of_descriptors() > 1) {
225+
map->instance_descriptors()->Sort();
226+
}
227+
}
228+
}
229+
167230
Deserializer::~Deserializer() {
168231
// TODO(svenpanne) Re-enable this assertion when v8 initialization is fixed.
169232
// DCHECK(source_.AtEOF());
@@ -288,6 +351,18 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
288351
new_code_objects_.Add(Code::cast(obj));
289352
}
290353
}
354+
if (FLAG_rehash_snapshot && can_rehash_ && !deserializing_user_code()) {
355+
if (obj->IsString()) {
356+
// Uninitialize hash field as we are going to reinitialize the hash seed.
357+
String* string = String::cast(obj);
358+
string->set_hash_field(String::kEmptyHashField);
359+
} else if (obj->IsTransitionArray() &&
360+
TransitionArray::cast(obj)->number_of_entries() > 1) {
361+
transition_arrays_.Add(TransitionArray::cast(obj));
362+
} else if (obj->IsMap()) {
363+
maps_.Add(Map::cast(obj));
364+
}
365+
}
291366
// Check alignment.
292367
DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), obj->RequiredAlignment()));
293368
return obj;

deps/v8/src/snapshot/deserializer.h

+18-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ class Deserializer : public SerializerDeserializer {
3737
external_reference_table_(NULL),
3838
deserialized_large_objects_(0),
3939
deserializing_user_code_(false),
40-
next_alignment_(kWordAligned) {
40+
next_alignment_(kWordAligned),
41+
can_rehash_(false) {
4142
DecodeReservation(data->Reservations());
4243
}
4344

@@ -59,6 +60,8 @@ class Deserializer : public SerializerDeserializer {
5960
attached_objects_ = attached_objects;
6061
}
6162

63+
void SetRehashability(bool v) { can_rehash_ = v; }
64+
6265
private:
6366
void VisitPointers(Object** start, Object** end) override;
6467

@@ -113,6 +116,15 @@ class Deserializer : public SerializerDeserializer {
113116
Object** CopyInNativesSource(Vector<const char> source_vector,
114117
Object** current);
115118

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

@@ -136,11 +148,16 @@ class Deserializer : public SerializerDeserializer {
136148
List<Code*> new_code_objects_;
137149
List<Handle<String> > new_internalized_strings_;
138150
List<Handle<Script> > new_scripts_;
151+
List<Map*> maps_;
152+
List<TransitionArray*> transition_arrays_;
139153

140154
bool deserializing_user_code_;
141155

142156
AllocationAlignment next_alignment_;
143157

158+
// TODO(6593): generalize rehashing, and remove this flag.
159+
bool can_rehash_;
160+
144161
DISALLOW_COPY_AND_ASSIGN(Deserializer);
145162
};
146163

deps/v8/src/snapshot/partial-serializer.cc

+26-7
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ PartialSerializer::PartialSerializer(Isolate* isolate,
1515
: Serializer(isolate, sink),
1616
startup_serializer_(startup_snapshot_serializer),
1717
global_object_(NULL),
18-
next_partial_cache_index_(0) {
18+
next_partial_cache_index_(0),
19+
rehashable_context_(nullptr),
20+
can_be_rehashed_(true) {
1921
InitializeCodeAddressMap();
2022
}
2123

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

2628
void PartialSerializer::Serialize(Object** o) {
27-
if ((*o)->IsContext()) {
29+
if ((*o)->IsNativeContext()) {
2830
Context* context = Context::cast(*o);
2931
global_object_ = context->global_object();
3032
back_reference_map()->AddGlobalProxy(context->global_proxy());
@@ -33,11 +35,14 @@ void PartialSerializer::Serialize(Object** o) {
3335
// and it's next context pointer may point to the code-stub context. Clear
3436
// it before serializing, it will get re-added to the context list
3537
// explicitly when it's loaded.
36-
if (context->IsNativeContext()) {
37-
context->set(Context::NEXT_CONTEXT_LINK,
38-
isolate_->heap()->undefined_value());
39-
DCHECK(!context->global_object()->IsUndefined());
40-
}
38+
context->set(Context::NEXT_CONTEXT_LINK,
39+
isolate_->heap()->undefined_value());
40+
DCHECK(!context->global_object()->IsUndefined());
41+
DCHECK_NULL(rehashable_context_);
42+
rehashable_context_ = context;
43+
} else {
44+
// We only do rehashing for native contexts.
45+
can_be_rehashed_ = false;
4146
}
4247
VisitPointer(o);
4348
SerializeDeferredObjects();
@@ -89,6 +94,8 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
8994
for (int i = 0; i < literals->length(); i++) literals->set_undefined(i);
9095
}
9196

97+
if (obj->IsHashTable()) CheckRehashability(obj);
98+
9299
// Object has not yet been serialized. Serialize it here.
93100
ObjectSerializer serializer(this, obj, sink_, how_to_code, where_to_point);
94101
serializer.Serialize();
@@ -119,5 +126,17 @@ bool PartialSerializer::ShouldBeInThePartialSnapshotCache(HeapObject* o) {
119126
startup_serializer_->isolate()->heap()->fixed_cow_array_map();
120127
}
121128

129+
void PartialSerializer::CheckRehashability(HeapObject* table) {
130+
DCHECK(table->IsHashTable());
131+
if (!can_be_rehashed_) return;
132+
// We can only correctly rehash if the global dictionary is the only hash
133+
// table that we deserialize.
134+
if (table == rehashable_context_->global_object()->global_dictionary()) {
135+
return;
136+
}
137+
if (table == rehashable_context_->template_instantiations_cache()) return;
138+
can_be_rehashed_ = false;
139+
}
140+
122141
} // namespace internal
123142
} // namespace v8

0 commit comments

Comments
 (0)