mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
deps: backport rehash strings after deserialization
Original commit messages:a2ab1353f6
[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 <cbruni@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Commit-Queue: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#46732}182caaf4a9
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 <ishell@chromium.org> Commit-Queue: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#46693} Fixes: https://github.com/nodejs/node/issues/14171 PR-URL: https://github.com/nodejs/node/pull/14345 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
This commit is contained in:
parent
9623ce572a
commit
8dce05fa71
8
configure
vendored
8
configure
vendored
@ -425,12 +425,12 @@ parser.add_option('--without-perfctr',
|
||||
# Dummy option for backwards compatibility
|
||||
parser.add_option('--with-snapshot',
|
||||
action='store_true',
|
||||
dest='with_snapshot',
|
||||
dest='unused_with_snapshot',
|
||||
help=optparse.SUPPRESS_HELP)
|
||||
|
||||
parser.add_option('--without-snapshot',
|
||||
action='store_true',
|
||||
dest='unused_without_snapshot',
|
||||
dest='without_snapshot',
|
||||
help=optparse.SUPPRESS_HELP)
|
||||
|
||||
parser.add_option('--without-ssl',
|
||||
@ -815,7 +815,7 @@ def configure_node(o):
|
||||
cross_compiling = (options.cross_compiling
|
||||
if options.cross_compiling is not None
|
||||
else target_arch != host_arch)
|
||||
want_snapshots = 1 if options.with_snapshot else 0
|
||||
want_snapshots = not options.without_snapshot
|
||||
o['variables']['want_separate_host_toolset'] = int(
|
||||
cross_compiling and want_snapshots)
|
||||
o['variables']['want_separate_host_toolset_mkpeephole'] = int(
|
||||
@ -962,7 +962,7 @@ def configure_v8(o):
|
||||
o['variables']['v8_optimized_debug'] = 0 # Compile with -O0 in debug builds.
|
||||
o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables.
|
||||
o['variables']['v8_promise_internal_field_count'] = 1 # Add internal field to promises for async hooks.
|
||||
o['variables']['v8_use_snapshot'] = b(options.with_snapshot)
|
||||
o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true'
|
||||
o['variables']['v8_trace_maps'] = 1 if options.trace_maps else 0
|
||||
o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform)
|
||||
o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8)
|
||||
|
2
deps/v8/include/v8-version.h
vendored
2
deps/v8/include/v8-version.h
vendored
@ -11,7 +11,7 @@
|
||||
#define V8_MAJOR_VERSION 5
|
||||
#define V8_MINOR_VERSION 9
|
||||
#define V8_BUILD_NUMBER 211
|
||||
#define V8_PATCH_LEVEL 38
|
||||
#define V8_PATCH_LEVEL 39
|
||||
|
||||
// Use 1 for candidates and 0 otherwise.
|
||||
// (Boolean macro values are not supported by all preprocessors.)
|
||||
|
13
deps/v8/src/api.cc
vendored
13
deps/v8/src/api.cc
vendored
@ -601,6 +601,9 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
isolate->heap()->SetSerializedGlobalProxySizes(*global_proxy_sizes);
|
||||
}
|
||||
|
||||
// We might rehash strings and re-sort descriptors. Clear the lookup cache.
|
||||
isolate->descriptor_lookup_cache()->Clear();
|
||||
|
||||
// If we don't do this then we end up with a stray root pointing at the
|
||||
// context even after we have disposed of the context.
|
||||
isolate->heap()->CollectAllAvailableGarbage(
|
||||
@ -642,11 +645,15 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
// Serialize each context with a new partial serializer.
|
||||
i::List<i::SnapshotData*> context_snapshots(num_additional_contexts + 1);
|
||||
|
||||
// TODO(6593): generalize rehashing, and remove this flag.
|
||||
bool can_be_rehashed = true;
|
||||
|
||||
{
|
||||
// The default snapshot does not support embedder fields.
|
||||
i::PartialSerializer partial_serializer(
|
||||
isolate, &startup_serializer, v8::SerializeInternalFieldsCallback());
|
||||
partial_serializer.Serialize(&default_context, false);
|
||||
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed();
|
||||
context_snapshots.Add(new i::SnapshotData(&partial_serializer));
|
||||
}
|
||||
|
||||
@ -654,10 +661,12 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
i::PartialSerializer partial_serializer(
|
||||
isolate, &startup_serializer, data->embedder_fields_serializers_[i]);
|
||||
partial_serializer.Serialize(&contexts[i], true);
|
||||
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed();
|
||||
context_snapshots.Add(new i::SnapshotData(&partial_serializer));
|
||||
}
|
||||
|
||||
startup_serializer.SerializeWeakReferencesAndDeferred();
|
||||
can_be_rehashed = can_be_rehashed && startup_serializer.can_be_rehashed();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (i::FLAG_external_reference_stats) {
|
||||
@ -666,8 +675,8 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
#endif // DEBUG
|
||||
|
||||
i::SnapshotData startup_snapshot(&startup_serializer);
|
||||
StartupData result =
|
||||
i::Snapshot::CreateSnapshotBlob(&startup_snapshot, &context_snapshots);
|
||||
StartupData result = i::Snapshot::CreateSnapshotBlob(
|
||||
&startup_snapshot, &context_snapshots, can_be_rehashed);
|
||||
|
||||
// Delete heap-allocated context snapshot instances.
|
||||
for (const auto& context_snapshot : context_snapshots) {
|
||||
|
6
deps/v8/src/bootstrapper.cc
vendored
6
deps/v8/src/bootstrapper.cc
vendored
@ -644,6 +644,8 @@ Handle<JSFunction> Genesis::GetThrowTypeErrorIntrinsic(
|
||||
DCHECK(false);
|
||||
}
|
||||
|
||||
JSObject::MigrateSlowToFast(function, 0, "Bootstrapping");
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
@ -1385,6 +1387,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
sloppy_function_map_writable_prototype_->SetConstructor(*function_fun);
|
||||
strict_function_map_writable_prototype_->SetConstructor(*function_fun);
|
||||
class_function_map_->SetConstructor(*function_fun);
|
||||
|
||||
JSObject::MigrateSlowToFast(function_fun, 0, "Bootstrapping");
|
||||
}
|
||||
|
||||
{
|
||||
@ -2204,6 +2208,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
info->set_length(1);
|
||||
native_context()->set_promise_reject_shared_fun(*info);
|
||||
}
|
||||
|
||||
JSObject::MigrateSlowToFast(promise_fun, 0, "Bootstrapping");
|
||||
}
|
||||
|
||||
{ // -- R e g E x p
|
||||
|
2
deps/v8/src/flag-definitions.h
vendored
2
deps/v8/src/flag-definitions.h
vendored
@ -987,6 +987,8 @@ DEFINE_BOOL(abort_on_stack_overflow, false,
|
||||
DEFINE_BOOL(randomize_hashes, true,
|
||||
"randomize hashes to avoid predictable hash collisions "
|
||||
"(with snapshots this option cannot override the baked-in seed)")
|
||||
DEFINE_BOOL(rehash_snapshot, true,
|
||||
"rehash strings from the snapshot to override the baked-in seed")
|
||||
DEFINE_INT(hash_seed, 0,
|
||||
"Fixed seed to use to hash property keys (0 means random)"
|
||||
"(with snapshots this option cannot override the baked-in seed)")
|
||||
|
17
deps/v8/src/heap/heap.cc
vendored
17
deps/v8/src/heap/heap.cc
vendored
@ -5546,14 +5546,7 @@ bool Heap::SetUp() {
|
||||
|
||||
// Set up the seed that is used to randomize the string hash function.
|
||||
DCHECK(hash_seed() == 0);
|
||||
if (FLAG_randomize_hashes) {
|
||||
if (FLAG_hash_seed == 0) {
|
||||
int rnd = isolate()->random_number_generator()->NextInt();
|
||||
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
|
||||
} else {
|
||||
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
|
||||
}
|
||||
}
|
||||
if (FLAG_randomize_hashes) InitializeHashSeed();
|
||||
|
||||
for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount);
|
||||
i++) {
|
||||
@ -5591,6 +5584,14 @@ bool Heap::SetUp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Heap::InitializeHashSeed() {
|
||||
if (FLAG_hash_seed == 0) {
|
||||
int rnd = isolate()->random_number_generator()->NextInt();
|
||||
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
|
||||
} else {
|
||||
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
|
||||
}
|
||||
}
|
||||
|
||||
bool Heap::CreateHeapObjects() {
|
||||
// Create initial maps.
|
||||
|
3
deps/v8/src/heap/heap.h
vendored
3
deps/v8/src/heap/heap.h
vendored
@ -994,6 +994,9 @@ class Heap {
|
||||
// without actually creating any objects.
|
||||
bool SetUp();
|
||||
|
||||
// (Re-)Initialize hash seed from flag or RNG.
|
||||
void InitializeHashSeed();
|
||||
|
||||
// Bootstraps the object heap with the core set of objects required to run.
|
||||
// Returns whether it succeeded.
|
||||
bool CreateHeapObjects();
|
||||
|
2
deps/v8/src/js/array.js
vendored
2
deps/v8/src/js/array.js
vendored
@ -1334,6 +1334,8 @@ var unscopables = {
|
||||
keys: true,
|
||||
};
|
||||
|
||||
%ToFastProperties(unscopables);
|
||||
|
||||
%AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables,
|
||||
DONT_ENUM | READ_ONLY);
|
||||
|
||||
|
11
deps/v8/src/objects.cc
vendored
11
deps/v8/src/objects.cc
vendored
@ -8823,7 +8823,13 @@ void Map::TraceAllTransitions(Map* map) {
|
||||
|
||||
void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
|
||||
Handle<Name> name, SimpleTransitionFlag flag) {
|
||||
if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) {
|
||||
Isolate* isolate = parent->GetIsolate();
|
||||
// Do not track transitions during bootstrap except for element transitions.
|
||||
if (isolate->bootstrapper()->IsActive() &&
|
||||
!name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
|
||||
return;
|
||||
}
|
||||
if (!parent->GetBackPointer()->IsUndefined(isolate)) {
|
||||
parent->set_owns_descriptors(false);
|
||||
} else {
|
||||
// |parent| is initial map and it must keep the ownership, there must be no
|
||||
@ -16779,6 +16785,9 @@ template class Dictionary<UnseededNumberDictionary,
|
||||
UnseededNumberDictionaryShape,
|
||||
uint32_t>;
|
||||
|
||||
template void
|
||||
HashTable<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Rehash(Handle<Name> key);
|
||||
|
||||
template Handle<SeededNumberDictionary>
|
||||
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
|
||||
Isolate*, int at_least_space_for, PretenureFlag pretenure,
|
||||
|
72
deps/v8/src/snapshot/deserializer.cc
vendored
72
deps/v8/src/snapshot/deserializer.cc
vendored
@ -121,6 +121,8 @@ void Deserializer::Deserialize(Isolate* isolate) {
|
||||
LOG_CODE_EVENT(isolate_, LogCodeObjects());
|
||||
LOG_CODE_EVENT(isolate_, LogBytecodeHandlers());
|
||||
LOG_CODE_EVENT(isolate_, LogCompiledFunctions());
|
||||
|
||||
if (FLAG_rehash_snapshot && can_rehash_) Rehash();
|
||||
}
|
||||
|
||||
MaybeHandle<Object> Deserializer::DeserializePartial(
|
||||
@ -151,6 +153,9 @@ MaybeHandle<Object> Deserializer::DeserializePartial(
|
||||
// changed and logging should be added to notify the profiler et al of the
|
||||
// new code, which also has to be flushed from instruction cache.
|
||||
CHECK_EQ(start_address, code_space->top());
|
||||
|
||||
if (FLAG_rehash_snapshot && can_rehash_) RehashContext(Context::cast(root));
|
||||
|
||||
return Handle<Object>(root, isolate);
|
||||
}
|
||||
|
||||
@ -177,6 +182,63 @@ MaybeHandle<HeapObject> Deserializer::DeserializeObject(Isolate* isolate) {
|
||||
}
|
||||
}
|
||||
|
||||
// We only really just need HashForObject here.
|
||||
class StringRehashKey : public HashTableKey {
|
||||
public:
|
||||
uint32_t HashForObject(Object* other) override {
|
||||
return String::cast(other)->Hash();
|
||||
}
|
||||
|
||||
static uint32_t StringHash(Object* obj) {
|
||||
UNREACHABLE();
|
||||
return String::cast(obj)->Hash();
|
||||
}
|
||||
|
||||
bool IsMatch(Object* string) override {
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t Hash() override {
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle<Object> AsHandle(Isolate* isolate) override {
|
||||
UNREACHABLE();
|
||||
return isolate->factory()->empty_string();
|
||||
}
|
||||
};
|
||||
|
||||
void Deserializer::Rehash() {
|
||||
DCHECK(can_rehash_);
|
||||
isolate_->heap()->InitializeHashSeed();
|
||||
if (FLAG_profile_deserialization) {
|
||||
PrintF("Re-initializing hash seed to %x\n",
|
||||
isolate_->heap()->hash_seed()->value());
|
||||
}
|
||||
StringRehashKey string_rehash_key;
|
||||
isolate_->heap()->string_table()->Rehash(&string_rehash_key);
|
||||
SortMapDescriptors();
|
||||
}
|
||||
|
||||
void Deserializer::RehashContext(Context* context) {
|
||||
DCHECK(can_rehash_);
|
||||
for (const auto& array : transition_arrays_) array->Sort();
|
||||
Handle<Name> dummy = isolate_->factory()->empty_string();
|
||||
context->global_object()->global_dictionary()->Rehash(dummy);
|
||||
SortMapDescriptors();
|
||||
}
|
||||
|
||||
void Deserializer::SortMapDescriptors() {
|
||||
for (const auto& address : allocated_maps_) {
|
||||
Map* map = Map::cast(HeapObject::FromAddress(address));
|
||||
if (map->instance_descriptors()->number_of_descriptors() > 1) {
|
||||
map->instance_descriptors()->Sort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Deserializer::~Deserializer() {
|
||||
#ifdef DEBUG
|
||||
// Do not perform checks if we aborted deserialization.
|
||||
@ -367,6 +429,16 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
|
||||
string->resource()));
|
||||
isolate_->heap()->RegisterExternalString(string);
|
||||
}
|
||||
if (FLAG_rehash_snapshot && can_rehash_ && !deserializing_user_code()) {
|
||||
if (obj->IsString()) {
|
||||
// Uninitialize hash field as we are going to reinitialize the hash seed.
|
||||
String* string = String::cast(obj);
|
||||
string->set_hash_field(String::kEmptyHashField);
|
||||
} else if (obj->IsTransitionArray() &&
|
||||
TransitionArray::cast(obj)->number_of_entries() > 1) {
|
||||
transition_arrays_.Add(TransitionArray::cast(obj));
|
||||
}
|
||||
}
|
||||
// Check alignment.
|
||||
DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), obj->RequiredAlignment()));
|
||||
return obj;
|
||||
|
18
deps/v8/src/snapshot/deserializer.h
vendored
18
deps/v8/src/snapshot/deserializer.h
vendored
@ -39,7 +39,8 @@ class Deserializer : public SerializerDeserializer {
|
||||
external_reference_table_(NULL),
|
||||
deserialized_large_objects_(0),
|
||||
deserializing_user_code_(deserializing_user_code),
|
||||
next_alignment_(kWordAligned) {
|
||||
next_alignment_(kWordAligned),
|
||||
can_rehash_(false) {
|
||||
DecodeReservation(data->Reservations());
|
||||
}
|
||||
|
||||
@ -62,6 +63,8 @@ class Deserializer : public SerializerDeserializer {
|
||||
attached_objects_.Add(attached_object);
|
||||
}
|
||||
|
||||
void SetRehashability(bool v) { can_rehash_ = v; }
|
||||
|
||||
private:
|
||||
void VisitPointers(Object** start, Object** end) override;
|
||||
|
||||
@ -117,6 +120,15 @@ class Deserializer : public SerializerDeserializer {
|
||||
// snapshot by chunk index and offset.
|
||||
HeapObject* GetBackReferencedObject(int space);
|
||||
|
||||
// Rehash after deserializing an isolate.
|
||||
void Rehash();
|
||||
|
||||
// Rehash after deserializing a context.
|
||||
void RehashContext(Context* context);
|
||||
|
||||
// Sort descriptors of deserialized maps using new string hashes.
|
||||
void SortMapDescriptors();
|
||||
|
||||
// Cached current isolate.
|
||||
Isolate* isolate_;
|
||||
|
||||
@ -144,11 +156,15 @@ class Deserializer : public SerializerDeserializer {
|
||||
List<AccessorInfo*> accessor_infos_;
|
||||
List<Handle<String> > new_internalized_strings_;
|
||||
List<Handle<Script> > new_scripts_;
|
||||
List<TransitionArray*> transition_arrays_;
|
||||
|
||||
bool deserializing_user_code_;
|
||||
|
||||
AllocationAlignment next_alignment_;
|
||||
|
||||
// TODO(6593): generalize rehashing, and remove this flag.
|
||||
bool can_rehash_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Deserializer);
|
||||
};
|
||||
|
||||
|
37
deps/v8/src/snapshot/partial-serializer.cc
vendored
37
deps/v8/src/snapshot/partial-serializer.cc
vendored
@ -15,7 +15,9 @@ PartialSerializer::PartialSerializer(
|
||||
v8::SerializeEmbedderFieldsCallback callback)
|
||||
: Serializer(isolate),
|
||||
startup_serializer_(startup_serializer),
|
||||
serialize_embedder_fields_(callback) {
|
||||
serialize_embedder_fields_(callback),
|
||||
rehashable_global_dictionary_(nullptr),
|
||||
can_be_rehashed_(true) {
|
||||
InitializeCodeAddressMap();
|
||||
}
|
||||
|
||||
@ -24,7 +26,7 @@ PartialSerializer::~PartialSerializer() {
|
||||
}
|
||||
|
||||
void PartialSerializer::Serialize(Object** o, bool include_global_proxy) {
|
||||
if ((*o)->IsContext()) {
|
||||
if ((*o)->IsNativeContext()) {
|
||||
Context* context = Context::cast(*o);
|
||||
reference_map()->AddAttachedReference(context->global_proxy());
|
||||
// The bootstrap snapshot has a code-stub context. When serializing the
|
||||
@ -32,14 +34,18 @@ void PartialSerializer::Serialize(Object** o, bool include_global_proxy) {
|
||||
// and it's next context pointer may point to the code-stub context. Clear
|
||||
// it before serializing, it will get re-added to the context list
|
||||
// explicitly when it's loaded.
|
||||
if (context->IsNativeContext()) {
|
||||
context->set(Context::NEXT_CONTEXT_LINK,
|
||||
isolate_->heap()->undefined_value());
|
||||
DCHECK(!context->global_object()->IsUndefined(context->GetIsolate()));
|
||||
// Reset math random cache to get fresh random numbers.
|
||||
context->set_math_random_index(Smi::kZero);
|
||||
context->set_math_random_cache(isolate_->heap()->undefined_value());
|
||||
}
|
||||
context->set(Context::NEXT_CONTEXT_LINK,
|
||||
isolate_->heap()->undefined_value());
|
||||
DCHECK(!context->global_object()->IsUndefined(context->GetIsolate()));
|
||||
// Reset math random cache to get fresh random numbers.
|
||||
context->set_math_random_index(Smi::kZero);
|
||||
context->set_math_random_cache(isolate_->heap()->undefined_value());
|
||||
DCHECK_NULL(rehashable_global_dictionary_);
|
||||
rehashable_global_dictionary_ =
|
||||
context->global_object()->global_dictionary();
|
||||
} else {
|
||||
// We only do rehashing for native contexts.
|
||||
can_be_rehashed_ = false;
|
||||
}
|
||||
VisitPointer(o);
|
||||
SerializeDeferredObjects();
|
||||
@ -104,6 +110,8 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->IsHashTable()) CheckRehashability(obj);
|
||||
|
||||
// Object has not yet been serialized. Serialize it here.
|
||||
ObjectSerializer serializer(this, obj, &sink_, how_to_code, where_to_point);
|
||||
serializer.Serialize();
|
||||
@ -152,5 +160,14 @@ void PartialSerializer::SerializeEmbedderFields() {
|
||||
sink_.Put(kSynchronize, "Finished with embedder fields data");
|
||||
}
|
||||
|
||||
void PartialSerializer::CheckRehashability(HeapObject* table) {
|
||||
DCHECK(table->IsHashTable());
|
||||
if (!can_be_rehashed_) return;
|
||||
// We can only correctly rehash if the global dictionary is the only hash
|
||||
// table that we deserialize.
|
||||
if (table == rehashable_global_dictionary_) return;
|
||||
can_be_rehashed_ = false;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
8
deps/v8/src/snapshot/partial-serializer.h
vendored
8
deps/v8/src/snapshot/partial-serializer.h
vendored
@ -23,6 +23,8 @@ class PartialSerializer : public Serializer {
|
||||
// Serialize the objects reachable from a single object pointer.
|
||||
void Serialize(Object** o, bool include_global_proxy);
|
||||
|
||||
bool can_be_rehashed() const { return can_be_rehashed_; }
|
||||
|
||||
private:
|
||||
void SerializeObject(HeapObject* o, HowToCode how_to_code,
|
||||
WhereToPoint where_to_point, int skip) override;
|
||||
@ -31,9 +33,15 @@ class PartialSerializer : public Serializer {
|
||||
|
||||
void SerializeEmbedderFields();
|
||||
|
||||
void CheckRehashability(HeapObject* table);
|
||||
|
||||
StartupSerializer* startup_serializer_;
|
||||
List<JSObject*> embedder_field_holders_;
|
||||
v8::SerializeEmbedderFieldsCallback serialize_embedder_fields_;
|
||||
GlobalDictionary* rehashable_global_dictionary_;
|
||||
// Indicates whether we only serialized hash tables that we can rehash.
|
||||
// TODO(yangguo): generalize rehashing, and remove this flag.
|
||||
bool can_be_rehashed_;
|
||||
DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
|
||||
};
|
||||
|
||||
|
13
deps/v8/src/snapshot/snapshot-common.cc
vendored
13
deps/v8/src/snapshot/snapshot-common.cc
vendored
@ -41,6 +41,7 @@ bool Snapshot::Initialize(Isolate* isolate) {
|
||||
Vector<const byte> startup_data = ExtractStartupData(blob);
|
||||
SnapshotData snapshot_data(startup_data);
|
||||
Deserializer deserializer(&snapshot_data);
|
||||
deserializer.SetRehashability(ExtractRehashability(blob));
|
||||
bool success = isolate->Init(&deserializer);
|
||||
if (FLAG_profile_deserialization) {
|
||||
double ms = timer.Elapsed().InMillisecondsF();
|
||||
@ -62,6 +63,7 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
|
||||
ExtractContextData(blob, static_cast<int>(context_index));
|
||||
SnapshotData snapshot_data(context_data);
|
||||
Deserializer deserializer(&snapshot_data);
|
||||
deserializer.SetRehashability(ExtractRehashability(blob));
|
||||
|
||||
MaybeHandle<Object> maybe_context = deserializer.DeserializePartial(
|
||||
isolate, global_proxy, embedder_fields_deserializer);
|
||||
@ -98,7 +100,7 @@ void ProfileDeserialization(const SnapshotData* startup_snapshot,
|
||||
|
||||
v8::StartupData Snapshot::CreateSnapshotBlob(
|
||||
const SnapshotData* startup_snapshot,
|
||||
const List<SnapshotData*>* context_snapshots) {
|
||||
const List<SnapshotData*>* context_snapshots, bool can_be_rehashed) {
|
||||
int num_contexts = context_snapshots->length();
|
||||
int startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
|
||||
int total_length = startup_snapshot_offset;
|
||||
@ -111,6 +113,8 @@ v8::StartupData Snapshot::CreateSnapshotBlob(
|
||||
|
||||
char* data = new char[total_length];
|
||||
memcpy(data + kNumberOfContextsOffset, &num_contexts, kInt32Size);
|
||||
int rehashability = can_be_rehashed ? 1 : 0;
|
||||
memcpy(data + kRehashabilityOffset, &rehashability, kInt32Size);
|
||||
int payload_offset = StartupSnapshotOffset(num_contexts);
|
||||
int payload_length = startup_snapshot->RawData().length();
|
||||
memcpy(data + payload_offset, startup_snapshot->RawData().start(),
|
||||
@ -143,6 +147,13 @@ int Snapshot::ExtractNumContexts(const v8::StartupData* data) {
|
||||
return num_contexts;
|
||||
}
|
||||
|
||||
bool Snapshot::ExtractRehashability(const v8::StartupData* data) {
|
||||
CHECK_LT(kRehashabilityOffset, data->raw_size);
|
||||
int rehashability;
|
||||
memcpy(&rehashability, data->data + kRehashabilityOffset, kInt32Size);
|
||||
return rehashability != 0;
|
||||
}
|
||||
|
||||
Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
|
||||
int num_contexts = ExtractNumContexts(data);
|
||||
int startup_offset = StartupSnapshotOffset(num_contexts);
|
||||
|
12
deps/v8/src/snapshot/snapshot.h
vendored
12
deps/v8/src/snapshot/snapshot.h
vendored
@ -73,7 +73,7 @@ class Snapshot : public AllStatic {
|
||||
|
||||
static v8::StartupData CreateSnapshotBlob(
|
||||
const SnapshotData* startup_snapshot,
|
||||
const List<SnapshotData*>* context_snapshots);
|
||||
const List<SnapshotData*>* context_snapshots, bool can_be_rehashed);
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool SnapshotIsValid(v8::StartupData* snapshot_blob);
|
||||
@ -81,14 +81,16 @@ class Snapshot : public AllStatic {
|
||||
|
||||
private:
|
||||
static int ExtractNumContexts(const v8::StartupData* data);
|
||||
static bool ExtractRehashability(const v8::StartupData* data);
|
||||
static Vector<const byte> ExtractStartupData(const v8::StartupData* data);
|
||||
static Vector<const byte> ExtractContextData(const v8::StartupData* data,
|
||||
int index);
|
||||
|
||||
// Snapshot blob layout:
|
||||
// [0] number of contexts N
|
||||
// [1] offset to context 0
|
||||
// [2] offset to context 1
|
||||
// [1] rehashability
|
||||
// [2] offset to context 0
|
||||
// [3] offset to context 1
|
||||
// ...
|
||||
// ... offset to context N - 1
|
||||
// ... startup snapshot data
|
||||
@ -96,8 +98,10 @@ class Snapshot : public AllStatic {
|
||||
// ... context 1 snapshot data
|
||||
|
||||
static const int kNumberOfContextsOffset = 0;
|
||||
// TODO(yangguo): generalize rehashing, and remove this flag.
|
||||
static const int kRehashabilityOffset = kNumberOfContextsOffset + kInt32Size;
|
||||
static const int kFirstContextOffsetOffset =
|
||||
kNumberOfContextsOffset + kInt32Size;
|
||||
kRehashabilityOffset + kInt32Size;
|
||||
|
||||
static int StartupSnapshotOffset(int num_contexts) {
|
||||
return kFirstContextOffsetOffset + num_contexts * kInt32Size;
|
||||
|
17
deps/v8/src/snapshot/startup-serializer.cc
vendored
17
deps/v8/src/snapshot/startup-serializer.cc
vendored
@ -16,7 +16,8 @@ StartupSerializer::StartupSerializer(
|
||||
: Serializer(isolate),
|
||||
clear_function_code_(function_code_handling ==
|
||||
v8::SnapshotCreator::FunctionCodeHandling::kClear),
|
||||
serializing_builtins_(false) {
|
||||
serializing_builtins_(false),
|
||||
can_be_rehashed_(true) {
|
||||
InitializeCodeAddressMap();
|
||||
}
|
||||
|
||||
@ -75,6 +76,8 @@ void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
||||
accessor_infos_.Add(info);
|
||||
}
|
||||
|
||||
if (obj->IsHashTable()) CheckRehashability(obj);
|
||||
|
||||
// Object has not yet been serialized. Serialize it here.
|
||||
ObjectSerializer object_serializer(this, obj, &sink_, how_to_code,
|
||||
where_to_point);
|
||||
@ -184,5 +187,17 @@ bool StartupSerializer::RootShouldBeSkipped(int root_index) {
|
||||
serializing_immortal_immovables_roots_;
|
||||
}
|
||||
|
||||
void StartupSerializer::CheckRehashability(HeapObject* table) {
|
||||
DCHECK(table->IsHashTable());
|
||||
if (!can_be_rehashed_) return;
|
||||
// We can only correctly rehash if the four hash tables below are the only
|
||||
// ones that we deserialize.
|
||||
if (table == isolate_->heap()->empty_slow_element_dictionary()) return;
|
||||
if (table == isolate_->heap()->empty_properties_dictionary()) return;
|
||||
if (table == isolate_->heap()->weak_object_to_code_table()) return;
|
||||
if (table == isolate_->heap()->string_table()) return;
|
||||
can_be_rehashed_ = false;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
8
deps/v8/src/snapshot/startup-serializer.h
vendored
8
deps/v8/src/snapshot/startup-serializer.h
vendored
@ -29,6 +29,8 @@ class StartupSerializer : public Serializer {
|
||||
|
||||
int PartialSnapshotCacheIndex(HeapObject* o);
|
||||
|
||||
bool can_be_rehashed() const { return can_be_rehashed_; }
|
||||
|
||||
private:
|
||||
class PartialCacheIndexMap {
|
||||
public:
|
||||
@ -68,12 +70,18 @@ class StartupSerializer : public Serializer {
|
||||
// roots. In the second pass, we serialize the rest.
|
||||
bool RootShouldBeSkipped(int root_index);
|
||||
|
||||
void CheckRehashability(HeapObject* hashtable);
|
||||
|
||||
bool clear_function_code_;
|
||||
bool serializing_builtins_;
|
||||
bool serializing_immortal_immovables_roots_;
|
||||
std::bitset<Heap::kStrongRootListLength> root_has_been_serialized_;
|
||||
PartialCacheIndexMap partial_cache_index_map_;
|
||||
List<AccessorInfo*> accessor_infos_;
|
||||
// Indicates whether we only serialized hash tables that we can rehash.
|
||||
// TODO(yangguo): generalize rehashing, and remove this flag.
|
||||
bool can_be_rehashed_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(StartupSerializer);
|
||||
};
|
||||
|
||||
|
2
deps/v8/src/transitions-inl.h
vendored
2
deps/v8/src/transitions-inl.h
vendored
@ -106,7 +106,6 @@ int TransitionArray::SearchName(Name* name, int* out_insertion_index) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
bool TransitionArray::IsSpecialTransition(Name* name) {
|
||||
if (!name->IsSymbol()) return false;
|
||||
Heap* heap = name->GetHeap();
|
||||
@ -115,7 +114,6 @@ bool TransitionArray::IsSpecialTransition(Name* name) {
|
||||
name == heap->elements_transition_symbol() ||
|
||||
name == heap->strict_function_transition_symbol();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int TransitionArray::CompareKeys(Name* key1, uint32_t hash1, PropertyKind kind1,
|
||||
|
42
deps/v8/src/transitions.cc
vendored
42
deps/v8/src/transitions.cc
vendored
@ -551,5 +551,47 @@ int TransitionArray::Search(PropertyKind kind, Name* name,
|
||||
if (transition == kNotFound) return kNotFound;
|
||||
return SearchDetails(transition, kind, attributes, out_insertion_index);
|
||||
}
|
||||
|
||||
void TransitionArray::Sort() {
|
||||
DisallowHeapAllocation no_gc;
|
||||
// In-place insertion sort.
|
||||
int length = number_of_transitions();
|
||||
for (int i = 1; i < length; i++) {
|
||||
Name* key = GetKey(i);
|
||||
Map* target = GetTarget(i);
|
||||
PropertyKind kind = kData;
|
||||
PropertyAttributes attributes = NONE;
|
||||
if (!IsSpecialTransition(key)) {
|
||||
PropertyDetails details = GetTargetDetails(key, target);
|
||||
kind = details.kind();
|
||||
attributes = details.attributes();
|
||||
}
|
||||
int j;
|
||||
for (j = i - 1; j >= 0; j--) {
|
||||
Name* temp_key = GetKey(j);
|
||||
Map* temp_target = GetTarget(j);
|
||||
PropertyKind temp_kind = kData;
|
||||
PropertyAttributes temp_attributes = NONE;
|
||||
if (!IsSpecialTransition(temp_key)) {
|
||||
PropertyDetails details = GetTargetDetails(temp_key, temp_target);
|
||||
temp_kind = details.kind();
|
||||
temp_attributes = details.attributes();
|
||||
}
|
||||
int cmp =
|
||||
CompareKeys(temp_key, temp_key->Hash(), temp_kind, temp_attributes,
|
||||
key, key->Hash(), kind, attributes);
|
||||
if (cmp > 0) {
|
||||
SetKey(j + 1, temp_key);
|
||||
SetTarget(j + 1, temp_target);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetKey(j + 1, key);
|
||||
SetTarget(j + 1, target);
|
||||
}
|
||||
DCHECK(IsSortedNoDuplicates());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
4
deps/v8/src/transitions.h
vendored
4
deps/v8/src/transitions.h
vendored
@ -190,15 +190,17 @@ class TransitionArray: public FixedArray {
|
||||
void TransitionArrayVerify();
|
||||
#endif
|
||||
|
||||
void Sort();
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsSortedNoDuplicates(int valid_entries = -1);
|
||||
static bool IsSortedNoDuplicates(Map* map);
|
||||
static bool IsConsistentWithBackPointers(Map* map);
|
||||
#endif
|
||||
|
||||
// Returns true for a non-property transitions like elements kind, observed
|
||||
// or frozen transitions.
|
||||
static inline bool IsSpecialTransition(Name* name);
|
||||
#endif
|
||||
|
||||
// Constant for denoting key was not found.
|
||||
static const int kNotFound = -1;
|
||||
|
21
deps/v8/test/cctest/heap/test-heap.cc
vendored
21
deps/v8/test/cctest/heap/test-heap.cc
vendored
@ -6609,5 +6609,26 @@ HEAP_TEST(Regress5831) {
|
||||
CHECK(chunk->NeverEvacuate());
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ReinitializeStringHashSeed) {
|
||||
// Enable rehashing and create an isolate and context.
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
for (int i = 1; i < 3; i++) {
|
||||
i::FLAG_hash_seed = 1337 * i;
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
CHECK_EQ(1337 * i,
|
||||
reinterpret_cast<i::Isolate*>(isolate)->heap()->HashSeed());
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
CHECK(!context.IsEmpty());
|
||||
v8::Context::Scope context_scope(context);
|
||||
}
|
||||
isolate->Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
45
deps/v8/test/cctest/test-serialize.cc
vendored
45
deps/v8/test/cctest/test-serialize.cc
vendored
@ -2547,6 +2547,51 @@ TEST(SnapshotCreatorIncludeGlobalProxy) {
|
||||
delete[] blob.data;
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ReinitializeStringHashSeedNotRehashable) {
|
||||
DisableAlwaysOpt();
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
i::FLAG_hash_seed = 42;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator;
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
// Create dictionary mode object.
|
||||
CompileRun(
|
||||
"var a = {};"
|
||||
"a.b = 1;"
|
||||
"a.c = 2;"
|
||||
"delete a.b;");
|
||||
ExpectInt32("a.c", 2);
|
||||
creator.SetDefaultContext(context);
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
i::FLAG_hash_seed = 1337;
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.snapshot_blob = &blob;
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
// Check that no rehashing has been performed.
|
||||
CHECK_EQ(42, reinterpret_cast<i::Isolate*>(isolate)->heap()->HashSeed());
|
||||
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("a.c", 2);
|
||||
}
|
||||
isolate->Dispose();
|
||||
delete[] blob.data;
|
||||
}
|
||||
|
||||
TEST(SerializationMemoryStats) {
|
||||
FLAG_profile_deserialization = true;
|
||||
FLAG_always_opt = false;
|
||||
|
1
deps/v8/test/mjsunit/regress/regress-5902.js
vendored
1
deps/v8/test/mjsunit/regress/regress-5902.js
vendored
@ -58,6 +58,5 @@ assertEquals(
|
||||
'Error.prototype',
|
||||
'EvalError.prototype', 'RangeError.prototype', 'ReferenceError.prototype',
|
||||
'SyntaxError.prototype', 'TypeError.prototype', 'URIError.prototype',
|
||||
'Map', 'Map.prototype.constructor', 'Set', 'Set.prototype.constructor'
|
||||
],
|
||||
log);
|
||||
|
Loading…
Reference in New Issue
Block a user