Commit 22861ce6 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[snapshot] Skip serialization of 'other strong roots'

... and weak context code lists. These are non-empty when an isolate
is running and the serializer cannot handle them.

Bug: v8:10416
Change-Id: I11a3d25dfd1980bcddae8b65c429df3c2cf16b19
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2172423
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarDan Elphick <delphick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67535}
parent 5c7f8740
...@@ -882,7 +882,7 @@ StartupData SnapshotCreator::CreateBlob( ...@@ -882,7 +882,7 @@ StartupData SnapshotCreator::CreateBlob(
data->created_ = true; data->created_ = true;
return i::Snapshot::Create(isolate, &contexts, embedder_fields_serializers, return i::Snapshot::Create(isolate, &contexts, embedder_fields_serializers,
&no_gc_from_here_on); no_gc_from_here_on);
} }
bool StartupData::CanBeRehashed() const { bool StartupData::CanBeRehashed() const {
......
...@@ -4572,12 +4572,6 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) { ...@@ -4572,12 +4572,6 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
isolate_->thread_manager()->Iterate(v); isolate_->thread_manager()->Iterate(v);
v->Synchronize(VisitorSynchronization::kThreadManager); v->Synchronize(VisitorSynchronization::kThreadManager);
// Iterate over other strong roots (currently only identity maps).
for (StrongRootsList* list = strong_roots_list_; list; list = list->next) {
v->VisitRootPointers(Root::kStrongRoots, nullptr, list->start, list->end);
}
v->Synchronize(VisitorSynchronization::kStrongRoots);
// Visitors in this block only run when not serializing. These include: // Visitors in this block only run when not serializing. These include:
// //
// - Thread-local and stack. // - Thread-local and stack.
...@@ -4637,6 +4631,13 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) { ...@@ -4637,6 +4631,13 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
} while (microtask_queue != default_microtask_queue); } while (microtask_queue != default_microtask_queue);
} }
// Iterate over other strong roots (currently only identity maps and
// deoptimization entries).
for (StrongRootsList* list = strong_roots_list_; list; list = list->next) {
v->VisitRootPointers(Root::kStrongRoots, nullptr, list->start, list->end);
}
v->Synchronize(VisitorSynchronization::kStrongRoots);
// Iterate over the startup object cache unless serializing or // Iterate over the startup object cache unless serializing or
// deserializing. // deserializing.
SerializerDeserializer::Iterate(isolate_, v); SerializerDeserializer::Iterate(isolate_, v);
......
...@@ -15,6 +15,54 @@ ...@@ -15,6 +15,54 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace {
// During serialization, puts the native context into a state understood by the
// serializer (e.g. by clearing lists of Code objects). After serialization,
// the original state is restored.
class SanitizeNativeContextScope final {
public:
SanitizeNativeContextScope(Isolate* isolate, NativeContext native_context,
bool allow_active_isolate_for_testing,
const DisallowHeapAllocation& no_gc)
: native_context_(native_context),
microtask_queue_(native_context.microtask_queue()),
optimized_code_list_(native_context.OptimizedCodeListHead()),
deoptimized_code_list_(native_context.DeoptimizedCodeListHead()) {
#ifdef DEBUG
if (!allow_active_isolate_for_testing) {
// Microtasks.
DCHECK_EQ(0, microtask_queue_->size());
DCHECK(!microtask_queue_->HasMicrotasksSuppressions());
DCHECK_EQ(0, microtask_queue_->GetMicrotasksScopeDepth());
DCHECK(microtask_queue_->DebugMicrotasksScopeDepthIsZero());
// Code lists.
DCHECK(optimized_code_list_.IsUndefined(isolate));
DCHECK(deoptimized_code_list_.IsUndefined(isolate));
}
#endif
Object undefined = ReadOnlyRoots(isolate).undefined_value();
native_context.set_microtask_queue(nullptr);
native_context.SetOptimizedCodeListHead(undefined);
native_context.SetDeoptimizedCodeListHead(undefined);
}
~SanitizeNativeContextScope() {
// Restore saved fields.
native_context_.SetDeoptimizedCodeListHead(optimized_code_list_);
native_context_.SetOptimizedCodeListHead(deoptimized_code_list_);
native_context_.set_microtask_queue(microtask_queue_);
}
private:
NativeContext native_context_;
MicrotaskQueue* const microtask_queue_;
const Object optimized_code_list_;
const Object deoptimized_code_list_;
};
} // namespace
ContextSerializer::ContextSerializer( ContextSerializer::ContextSerializer(
Isolate* isolate, Snapshot::SerializerFlags flags, Isolate* isolate, Snapshot::SerializerFlags flags,
StartupSerializer* startup_serializer, StartupSerializer* startup_serializer,
...@@ -31,7 +79,8 @@ ContextSerializer::~ContextSerializer() { ...@@ -31,7 +79,8 @@ ContextSerializer::~ContextSerializer() {
OutputStatistics("ContextSerializer"); OutputStatistics("ContextSerializer");
} }
void ContextSerializer::Serialize(Context* o, bool include_global_proxy) { void ContextSerializer::Serialize(Context* o,
const DisallowHeapAllocation& no_gc) {
context_ = *o; context_ = *o;
DCHECK(context_.IsNativeContext()); DCHECK(context_.IsNativeContext());
reference_map()->AddAttachedReference( reference_map()->AddAttachedReference(
...@@ -41,22 +90,17 @@ void ContextSerializer::Serialize(Context* o, bool include_global_proxy) { ...@@ -41,22 +90,17 @@ void ContextSerializer::Serialize(Context* o, bool include_global_proxy) {
// and it's next context pointer may point to the code-stub context. Clear // 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 // it before serializing, it will get re-added to the context list
// explicitly when it's loaded. // explicitly when it's loaded.
// TODO(v8:10416): These mutations should not observably affect the running
// context.
context_.set(Context::NEXT_CONTEXT_LINK, context_.set(Context::NEXT_CONTEXT_LINK,
ReadOnlyRoots(isolate()).undefined_value()); ReadOnlyRoots(isolate()).undefined_value());
DCHECK(!context_.global_object().IsUndefined()); DCHECK(!context_.global_object().IsUndefined());
// Reset math random cache to get fresh random numbers. // Reset math random cache to get fresh random numbers.
MathRandom::ResetContext(context_); MathRandom::ResetContext(context_);
MicrotaskQueue* microtask_queue = context_.native_context().microtask_queue(); SanitizeNativeContextScope sanitize_native_context(
#ifdef DEBUG isolate(), context_.native_context(), allow_active_isolate_for_testing(),
if (!allow_microtasks_for_testing()) { no_gc);
DCHECK_EQ(0, microtask_queue->size());
DCHECK(!microtask_queue->HasMicrotasksSuppressions());
DCHECK_EQ(0, microtask_queue->GetMicrotasksScopeDepth());
DCHECK(microtask_queue->DebugMicrotasksScopeDepthIsZero());
}
#endif
context_.native_context().set_microtask_queue(nullptr);
VisitRootPointer(Root::kStartupObjectCache, nullptr, FullObjectSlot(o)); VisitRootPointer(Root::kStartupObjectCache, nullptr, FullObjectSlot(o));
SerializeDeferredObjects(); SerializeDeferredObjects();
...@@ -69,9 +113,6 @@ void ContextSerializer::Serialize(Context* o, bool include_global_proxy) { ...@@ -69,9 +113,6 @@ void ContextSerializer::Serialize(Context* o, bool include_global_proxy) {
} }
Pad(); Pad();
// Restore the microtask queue.
context_.native_context().set_microtask_queue(microtask_queue);
} }
void ContextSerializer::SerializeObject(HeapObject obj) { void ContextSerializer::SerializeObject(HeapObject obj) {
......
...@@ -23,17 +23,14 @@ class V8_EXPORT_PRIVATE ContextSerializer : public Serializer { ...@@ -23,17 +23,14 @@ class V8_EXPORT_PRIVATE ContextSerializer : public Serializer {
~ContextSerializer() override; ~ContextSerializer() override;
// Serialize the objects reachable from a single object pointer. // Serialize the objects reachable from a single object pointer.
void Serialize(Context* o, bool include_global_proxy); void Serialize(Context* o, const DisallowHeapAllocation& no_gc);
bool can_be_rehashed() const { return can_be_rehashed_; } bool can_be_rehashed() const { return can_be_rehashed_; }
private: private:
void SerializeObject(HeapObject o) override; void SerializeObject(HeapObject o) override;
bool ShouldBeInTheStartupObjectCache(HeapObject o); bool ShouldBeInTheStartupObjectCache(HeapObject o);
bool SerializeJSObjectWithEmbedderFields(Object obj); bool SerializeJSObjectWithEmbedderFields(Object obj);
void CheckRehashability(HeapObject obj); void CheckRehashability(HeapObject obj);
StartupSerializer* startup_serializer_; StartupSerializer* startup_serializer_;
......
...@@ -51,7 +51,7 @@ void ReadOnlySerializer::SerializeReadOnlyRoots() { ...@@ -51,7 +51,7 @@ void ReadOnlySerializer::SerializeReadOnlyRoots() {
// No active threads. // No active threads.
CHECK_NULL(isolate()->thread_manager()->FirstThreadStateInUse()); CHECK_NULL(isolate()->thread_manager()->FirstThreadStateInUse());
// No active or weak handles. // No active or weak handles.
CHECK_IMPLIES(!allow_open_handles_for_testing(), CHECK_IMPLIES(!allow_active_isolate_for_testing(),
isolate()->handle_scope_implementer()->blocks()->empty()); isolate()->handle_scope_implementer()->blocks()->empty());
ReadOnlyRoots(isolate()).Iterate(this); ReadOnlyRoots(isolate()).Iterate(this);
......
...@@ -268,11 +268,8 @@ class Serializer : public SerializerDeserializer { ...@@ -268,11 +268,8 @@ class Serializer : public SerializerDeserializer {
bool allow_unknown_external_references_for_testing() const { bool allow_unknown_external_references_for_testing() const {
return (flags_ & Snapshot::kAllowUnknownExternalReferencesForTesting) != 0; return (flags_ & Snapshot::kAllowUnknownExternalReferencesForTesting) != 0;
} }
bool allow_open_handles_for_testing() const { bool allow_active_isolate_for_testing() const {
return (flags_ & Snapshot::kAllowOpenHandlesForTesting) != 0; return (flags_ & Snapshot::kAllowActiveIsolateForTesting) != 0;
}
bool allow_microtasks_for_testing() const {
return (flags_ & Snapshot::kAllowMicrotasksForTesting) != 0;
} }
private: private:
......
...@@ -203,10 +203,8 @@ void Snapshot::SerializeDeserializeAndVerifyForTesting( ...@@ -203,10 +203,8 @@ void Snapshot::SerializeDeserializeAndVerifyForTesting(
Snapshot::SerializerFlags flags( Snapshot::SerializerFlags flags(
Snapshot::kAllowUnknownExternalReferencesForTesting | Snapshot::kAllowUnknownExternalReferencesForTesting |
Snapshot::kAllowOpenHandlesForTesting | Snapshot::kAllowActiveIsolateForTesting);
Snapshot::kAllowMicrotasksForTesting); serialized_data = Snapshot::Create(isolate, *default_context, no_gc, flags);
serialized_data =
Snapshot::Create(isolate, *default_context, &no_gc, flags);
auto_delete_serialized_data.reset(serialized_data.data); auto_delete_serialized_data.reset(serialized_data.data);
} }
...@@ -266,7 +264,7 @@ v8::StartupData Snapshot::Create( ...@@ -266,7 +264,7 @@ v8::StartupData Snapshot::Create(
Isolate* isolate, std::vector<Context>* contexts, Isolate* isolate, std::vector<Context>* contexts,
const std::vector<SerializeInternalFieldsCallback>& const std::vector<SerializeInternalFieldsCallback>&
embedder_fields_serializers, embedder_fields_serializers,
const DisallowHeapAllocation* no_gc, SerializerFlags flags) { const DisallowHeapAllocation& no_gc, SerializerFlags flags) {
DCHECK_EQ(contexts->size(), embedder_fields_serializers.size()); DCHECK_EQ(contexts->size(), embedder_fields_serializers.size());
DCHECK_GT(contexts->size(), 0); DCHECK_GT(contexts->size(), 0);
...@@ -285,11 +283,9 @@ v8::StartupData Snapshot::Create( ...@@ -285,11 +283,9 @@ v8::StartupData Snapshot::Create(
bool can_be_rehashed = true; bool can_be_rehashed = true;
for (int i = 0; i < num_contexts; i++) { for (int i = 0; i < num_contexts; i++) {
const bool is_default_context = (i == 0);
const bool include_global_proxy = !is_default_context;
ContextSerializer context_serializer(isolate, flags, &startup_serializer, ContextSerializer context_serializer(isolate, flags, &startup_serializer,
embedder_fields_serializers[i]); embedder_fields_serializers[i]);
context_serializer.Serialize(&contexts->at(i), include_global_proxy); context_serializer.Serialize(&contexts->at(i), no_gc);
can_be_rehashed = can_be_rehashed && context_serializer.can_be_rehashed(); can_be_rehashed = can_be_rehashed && context_serializer.can_be_rehashed();
context_snapshots.push_back(new SnapshotData(&context_serializer)); context_snapshots.push_back(new SnapshotData(&context_serializer));
} }
...@@ -316,7 +312,7 @@ v8::StartupData Snapshot::Create( ...@@ -316,7 +312,7 @@ v8::StartupData Snapshot::Create(
// static // static
v8::StartupData Snapshot::Create(Isolate* isolate, Context default_context, v8::StartupData Snapshot::Create(Isolate* isolate, Context default_context,
const DisallowHeapAllocation* no_gc, const DisallowHeapAllocation& no_gc,
SerializerFlags flags) { SerializerFlags flags) {
std::vector<Context> contexts{default_context}; std::vector<Context> contexts{default_context};
std::vector<SerializeInternalFieldsCallback> callbacks{{}}; std::vector<SerializeInternalFieldsCallback> callbacks{{}};
......
...@@ -27,14 +27,15 @@ class Snapshot : public AllStatic { ...@@ -27,14 +27,15 @@ class Snapshot : public AllStatic {
// different isolate or a different process. // different isolate or a different process.
// If unset, all external references must be known to the encoder. // If unset, all external references must be known to the encoder.
kAllowUnknownExternalReferencesForTesting = 1 << 0, kAllowUnknownExternalReferencesForTesting = 1 << 0,
// If set, serialization can succeed even with open handles. The // If set, the serializer enters a more permissive mode which allows
// contents of open handle scopes are *not* serialized. // serialization of a currently active, running isolate. This has multiple
// If unset, no open handles are allowed to ensure the snapshot // effects; for example, open handles are allowed, microtasks may exist,
// contains no unexpected objects. // etc. Note that in this mode, the serializer is allowed to skip
kAllowOpenHandlesForTesting = 1 << 1, // visitation of certain problematic areas even if they are non-empty. The
// As above, if set we allow but do *not* serialize existing microtasks. // resulting snapshot is not guaranteed to result in a runnable context
// If unset, the microtask queue must be empty. // after deserialization.
kAllowMicrotasksForTesting = 1 << 2, // If unset, we assert that these previously mentioned areas are empty.
kAllowActiveIsolateForTesting = 1 << 1,
}; };
using SerializerFlags = base::Flags<SerializerFlag>; using SerializerFlags = base::Flags<SerializerFlag>;
V8_EXPORT_PRIVATE static constexpr SerializerFlags kDefaultSerializerFlags = V8_EXPORT_PRIVATE static constexpr SerializerFlags kDefaultSerializerFlags =
...@@ -47,13 +48,13 @@ class Snapshot : public AllStatic { ...@@ -47,13 +48,13 @@ class Snapshot : public AllStatic {
Isolate* isolate, std::vector<Context>* contexts, Isolate* isolate, std::vector<Context>* contexts,
const std::vector<SerializeInternalFieldsCallback>& const std::vector<SerializeInternalFieldsCallback>&
embedder_fields_serializers, embedder_fields_serializers,
const DisallowHeapAllocation* no_gc, const DisallowHeapAllocation& no_gc,
SerializerFlags flags = kDefaultSerializerFlags); SerializerFlags flags = kDefaultSerializerFlags);
// Convenience helper for the above when only serializing a single context. // Convenience helper for the above when only serializing a single context.
static v8::StartupData Create( static v8::StartupData Create(
Isolate* isolate, Context default_context, Isolate* isolate, Context default_context,
const DisallowHeapAllocation* no_gc, const DisallowHeapAllocation& no_gc,
SerializerFlags flags = kDefaultSerializerFlags); SerializerFlags flags = kDefaultSerializerFlags);
// ---------------- Deserialization ----------------------------------------- // ---------------- Deserialization -----------------------------------------
......
...@@ -146,7 +146,7 @@ void StartupSerializer::SerializeStrongReferences() { ...@@ -146,7 +146,7 @@ void StartupSerializer::SerializeStrongReferences() {
// No active threads. // No active threads.
CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse()); CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
// No active or weak handles. // No active or weak handles.
CHECK_IMPLIES(!allow_open_handles_for_testing(), CHECK_IMPLIES(!allow_active_isolate_for_testing(),
isolate->handle_scope_implementer()->blocks()->empty()); isolate->handle_scope_implementer()->blocks()->empty());
// Visit smi roots and immortal immovables first to make sure they end up in // Visit smi roots and immortal immovables first to make sure they end up in
......
...@@ -381,6 +381,7 @@ static void SerializeContext(Vector<const byte>* startup_blob_out, ...@@ -381,6 +381,7 @@ static void SerializeContext(Vector<const byte>* startup_blob_out,
env.Reset(); env.Reset();
DisallowHeapAllocation no_gc;
SnapshotByteSink read_only_sink; SnapshotByteSink read_only_sink;
ReadOnlySerializer read_only_serializer(isolate, ReadOnlySerializer read_only_serializer(isolate,
Snapshot::kDefaultSerializerFlags); Snapshot::kDefaultSerializerFlags);
...@@ -395,7 +396,7 @@ static void SerializeContext(Vector<const byte>* startup_blob_out, ...@@ -395,7 +396,7 @@ static void SerializeContext(Vector<const byte>* startup_blob_out,
ContextSerializer context_serializer( ContextSerializer context_serializer(
isolate, Snapshot::kDefaultSerializerFlags, &startup_serializer, isolate, Snapshot::kDefaultSerializerFlags, &startup_serializer,
v8::SerializeInternalFieldsCallback()); v8::SerializeInternalFieldsCallback());
context_serializer.Serialize(&raw_context, false); context_serializer.Serialize(&raw_context, no_gc);
startup_serializer.SerializeWeakReferencesAndDeferred(); startup_serializer.SerializeWeakReferencesAndDeferred();
...@@ -530,6 +531,7 @@ static void SerializeCustomContext(Vector<const byte>* startup_blob_out, ...@@ -530,6 +531,7 @@ static void SerializeCustomContext(Vector<const byte>* startup_blob_out,
env.Reset(); env.Reset();
DisallowHeapAllocation no_gc;
SnapshotByteSink read_only_sink; SnapshotByteSink read_only_sink;
ReadOnlySerializer read_only_serializer(isolate, ReadOnlySerializer read_only_serializer(isolate,
Snapshot::kDefaultSerializerFlags); Snapshot::kDefaultSerializerFlags);
...@@ -544,7 +546,7 @@ static void SerializeCustomContext(Vector<const byte>* startup_blob_out, ...@@ -544,7 +546,7 @@ static void SerializeCustomContext(Vector<const byte>* startup_blob_out,
ContextSerializer context_serializer( ContextSerializer context_serializer(
isolate, Snapshot::kDefaultSerializerFlags, &startup_serializer, isolate, Snapshot::kDefaultSerializerFlags, &startup_serializer,
v8::SerializeInternalFieldsCallback()); v8::SerializeInternalFieldsCallback());
context_serializer.Serialize(&raw_context, false); context_serializer.Serialize(&raw_context, no_gc);
startup_serializer.SerializeWeakReferencesAndDeferred(); startup_serializer.SerializeWeakReferencesAndDeferred();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment