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(
data->created_ = true;
return i::Snapshot::Create(isolate, &contexts, embedder_fields_serializers,
&no_gc_from_here_on);
no_gc_from_here_on);
}
bool StartupData::CanBeRehashed() const {
......
......@@ -4572,12 +4572,6 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
isolate_->thread_manager()->Iterate(v);
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:
//
// - Thread-local and stack.
......@@ -4637,6 +4631,13 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
} 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
// deserializing.
SerializerDeserializer::Iterate(isolate_, v);
......
......@@ -15,6 +15,54 @@
namespace v8 {
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(
Isolate* isolate, Snapshot::SerializerFlags flags,
StartupSerializer* startup_serializer,
......@@ -31,7 +79,8 @@ ContextSerializer::~ContextSerializer() {
OutputStatistics("ContextSerializer");
}
void ContextSerializer::Serialize(Context* o, bool include_global_proxy) {
void ContextSerializer::Serialize(Context* o,
const DisallowHeapAllocation& no_gc) {
context_ = *o;
DCHECK(context_.IsNativeContext());
reference_map()->AddAttachedReference(
......@@ -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
// it before serializing, it will get re-added to the context list
// explicitly when it's loaded.
// TODO(v8:10416): These mutations should not observably affect the running
// context.
context_.set(Context::NEXT_CONTEXT_LINK,
ReadOnlyRoots(isolate()).undefined_value());
DCHECK(!context_.global_object().IsUndefined());
// Reset math random cache to get fresh random numbers.
MathRandom::ResetContext(context_);
MicrotaskQueue* microtask_queue = context_.native_context().microtask_queue();
#ifdef DEBUG
if (!allow_microtasks_for_testing()) {
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);
SanitizeNativeContextScope sanitize_native_context(
isolate(), context_.native_context(), allow_active_isolate_for_testing(),
no_gc);
VisitRootPointer(Root::kStartupObjectCache, nullptr, FullObjectSlot(o));
SerializeDeferredObjects();
......@@ -69,9 +113,6 @@ void ContextSerializer::Serialize(Context* o, bool include_global_proxy) {
}
Pad();
// Restore the microtask queue.
context_.native_context().set_microtask_queue(microtask_queue);
}
void ContextSerializer::SerializeObject(HeapObject obj) {
......
......@@ -23,17 +23,14 @@ class V8_EXPORT_PRIVATE ContextSerializer : public Serializer {
~ContextSerializer() override;
// 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_; }
private:
void SerializeObject(HeapObject o) override;
bool ShouldBeInTheStartupObjectCache(HeapObject o);
bool SerializeJSObjectWithEmbedderFields(Object obj);
void CheckRehashability(HeapObject obj);
StartupSerializer* startup_serializer_;
......
......@@ -51,7 +51,7 @@ void ReadOnlySerializer::SerializeReadOnlyRoots() {
// No active threads.
CHECK_NULL(isolate()->thread_manager()->FirstThreadStateInUse());
// 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());
ReadOnlyRoots(isolate()).Iterate(this);
......
......@@ -268,11 +268,8 @@ class Serializer : public SerializerDeserializer {
bool allow_unknown_external_references_for_testing() const {
return (flags_ & Snapshot::kAllowUnknownExternalReferencesForTesting) != 0;
}
bool allow_open_handles_for_testing() const {
return (flags_ & Snapshot::kAllowOpenHandlesForTesting) != 0;
}
bool allow_microtasks_for_testing() const {
return (flags_ & Snapshot::kAllowMicrotasksForTesting) != 0;
bool allow_active_isolate_for_testing() const {
return (flags_ & Snapshot::kAllowActiveIsolateForTesting) != 0;
}
private:
......
......@@ -203,10 +203,8 @@ void Snapshot::SerializeDeserializeAndVerifyForTesting(
Snapshot::SerializerFlags flags(
Snapshot::kAllowUnknownExternalReferencesForTesting |
Snapshot::kAllowOpenHandlesForTesting |
Snapshot::kAllowMicrotasksForTesting);
serialized_data =
Snapshot::Create(isolate, *default_context, &no_gc, flags);
Snapshot::kAllowActiveIsolateForTesting);
serialized_data = Snapshot::Create(isolate, *default_context, no_gc, flags);
auto_delete_serialized_data.reset(serialized_data.data);
}
......@@ -266,7 +264,7 @@ v8::StartupData Snapshot::Create(
Isolate* isolate, std::vector<Context>* contexts,
const std::vector<SerializeInternalFieldsCallback>&
embedder_fields_serializers,
const DisallowHeapAllocation* no_gc, SerializerFlags flags) {
const DisallowHeapAllocation& no_gc, SerializerFlags flags) {
DCHECK_EQ(contexts->size(), embedder_fields_serializers.size());
DCHECK_GT(contexts->size(), 0);
......@@ -285,11 +283,9 @@ v8::StartupData Snapshot::Create(
bool can_be_rehashed = true;
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,
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();
context_snapshots.push_back(new SnapshotData(&context_serializer));
}
......@@ -316,7 +312,7 @@ v8::StartupData Snapshot::Create(
// static
v8::StartupData Snapshot::Create(Isolate* isolate, Context default_context,
const DisallowHeapAllocation* no_gc,
const DisallowHeapAllocation& no_gc,
SerializerFlags flags) {
std::vector<Context> contexts{default_context};
std::vector<SerializeInternalFieldsCallback> callbacks{{}};
......
......@@ -27,14 +27,15 @@ class Snapshot : public AllStatic {
// different isolate or a different process.
// If unset, all external references must be known to the encoder.
kAllowUnknownExternalReferencesForTesting = 1 << 0,
// If set, serialization can succeed even with open handles. The
// contents of open handle scopes are *not* serialized.
// If unset, no open handles are allowed to ensure the snapshot
// contains no unexpected objects.
kAllowOpenHandlesForTesting = 1 << 1,
// As above, if set we allow but do *not* serialize existing microtasks.
// If unset, the microtask queue must be empty.
kAllowMicrotasksForTesting = 1 << 2,
// If set, the serializer enters a more permissive mode which allows
// serialization of a currently active, running isolate. This has multiple
// effects; for example, open handles are allowed, microtasks may exist,
// etc. Note that in this mode, the serializer is allowed to skip
// visitation of certain problematic areas even if they are non-empty. The
// resulting snapshot is not guaranteed to result in a runnable context
// after deserialization.
// If unset, we assert that these previously mentioned areas are empty.
kAllowActiveIsolateForTesting = 1 << 1,
};
using SerializerFlags = base::Flags<SerializerFlag>;
V8_EXPORT_PRIVATE static constexpr SerializerFlags kDefaultSerializerFlags =
......@@ -47,13 +48,13 @@ class Snapshot : public AllStatic {
Isolate* isolate, std::vector<Context>* contexts,
const std::vector<SerializeInternalFieldsCallback>&
embedder_fields_serializers,
const DisallowHeapAllocation* no_gc,
const DisallowHeapAllocation& no_gc,
SerializerFlags flags = kDefaultSerializerFlags);
// Convenience helper for the above when only serializing a single context.
static v8::StartupData Create(
Isolate* isolate, Context default_context,
const DisallowHeapAllocation* no_gc,
const DisallowHeapAllocation& no_gc,
SerializerFlags flags = kDefaultSerializerFlags);
// ---------------- Deserialization -----------------------------------------
......
......@@ -146,7 +146,7 @@ void StartupSerializer::SerializeStrongReferences() {
// No active threads.
CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
// 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());
// 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,
env.Reset();
DisallowHeapAllocation no_gc;
SnapshotByteSink read_only_sink;
ReadOnlySerializer read_only_serializer(isolate,
Snapshot::kDefaultSerializerFlags);
......@@ -395,7 +396,7 @@ static void SerializeContext(Vector<const byte>* startup_blob_out,
ContextSerializer context_serializer(
isolate, Snapshot::kDefaultSerializerFlags, &startup_serializer,
v8::SerializeInternalFieldsCallback());
context_serializer.Serialize(&raw_context, false);
context_serializer.Serialize(&raw_context, no_gc);
startup_serializer.SerializeWeakReferencesAndDeferred();
......@@ -530,6 +531,7 @@ static void SerializeCustomContext(Vector<const byte>* startup_blob_out,
env.Reset();
DisallowHeapAllocation no_gc;
SnapshotByteSink read_only_sink;
ReadOnlySerializer read_only_serializer(isolate,
Snapshot::kDefaultSerializerFlags);
......@@ -544,7 +546,7 @@ static void SerializeCustomContext(Vector<const byte>* startup_blob_out,
ContextSerializer context_serializer(
isolate, Snapshot::kDefaultSerializerFlags, &startup_serializer,
v8::SerializeInternalFieldsCallback());
context_serializer.Serialize(&raw_context, false);
context_serializer.Serialize(&raw_context, no_gc);
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