[snapshot] Create a ReadOnly snapshot
In preparation for sharing RO_SPACE between all Isolates within a process, this first pulls RO_SPACE out of the Startup snapshot and puts it in its own ReadOnly snapshot. The snapshot is first populated with the read-only roots. After that the StartupSerializer serializes as before but starting from the first mutable root. References to objects in the ReadOnly snapshot that aren't themselves roots are added to a new cache called ReadOnlyObjectCache which functions like the PartialSnapshotCache but lives in the ReadOnlySerializer rather than the StartupSerializer. These cache entries are referenced using a new bytecode: ReadOnlyObjectCache. (To make room for this, the ApiReference bytecode has been moved). To reduce code duplication, the StartupSerializer has been refactored to create a new base class RootSerializer, which ReadOnlySerializer also subclasses. The base class is responsible primarily for keeping track of already serialized roots and visiting the roots. Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng Change-Id: Iff26042886130ae22eccf2e11b35f6f226f4a792 Bug: v8:8191 Reviewed-on: https://chromium-review.googlesource.com/c/1244676 Commit-Queue: Dan Elphick <delphick@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#56681}
This commit is contained in:
parent
fac6f63eb8
commit
f602712f6f
6
BUILD.gn
6
BUILD.gn
@ -2476,7 +2476,13 @@ v8_source_set("v8_base") {
|
||||
"src/snapshot/partial-deserializer.h",
|
||||
"src/snapshot/partial-serializer.cc",
|
||||
"src/snapshot/partial-serializer.h",
|
||||
"src/snapshot/read-only-deserializer.cc",
|
||||
"src/snapshot/read-only-deserializer.h",
|
||||
"src/snapshot/read-only-serializer.cc",
|
||||
"src/snapshot/read-only-serializer.h",
|
||||
"src/snapshot/references.h",
|
||||
"src/snapshot/roots-serializer.cc",
|
||||
"src/snapshot/roots-serializer.h",
|
||||
"src/snapshot/serializer-common.cc",
|
||||
"src/snapshot/serializer-common.h",
|
||||
"src/snapshot/serializer.cc",
|
||||
|
15
src/api.cc
15
src/api.cc
@ -79,7 +79,10 @@
|
||||
#include "src/snapshot/builtin-serializer.h"
|
||||
#include "src/snapshot/code-serializer.h"
|
||||
#include "src/snapshot/natives.h"
|
||||
#include "src/snapshot/partial-serializer.h"
|
||||
#include "src/snapshot/read-only-serializer.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
#include "src/snapshot/startup-serializer.h"
|
||||
#include "src/startup-data-util.h"
|
||||
#include "src/string-hasher.h"
|
||||
#include "src/tracing/trace-event.h"
|
||||
@ -795,7 +798,10 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
}
|
||||
}
|
||||
|
||||
i::StartupSerializer startup_serializer(isolate);
|
||||
i::ReadOnlySerializer read_only_serializer(isolate);
|
||||
read_only_serializer.SerializeReadOnlyRoots();
|
||||
|
||||
i::StartupSerializer startup_serializer(isolate, &read_only_serializer);
|
||||
startup_serializer.SerializeStrongReferences();
|
||||
|
||||
// Serialize each context with a new partial serializer.
|
||||
@ -825,10 +831,15 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
startup_serializer.SerializeWeakReferencesAndDeferred();
|
||||
can_be_rehashed = can_be_rehashed && startup_serializer.can_be_rehashed();
|
||||
|
||||
read_only_serializer.FinalizeSerialization();
|
||||
can_be_rehashed = can_be_rehashed && read_only_serializer.can_be_rehashed();
|
||||
|
||||
i::SnapshotData read_only_snapshot(&read_only_serializer);
|
||||
i::SnapshotData startup_snapshot(&startup_serializer);
|
||||
i::BuiltinSnapshotData builtin_snapshot(&builtin_serializer);
|
||||
StartupData result = i::Snapshot::CreateSnapshotBlob(
|
||||
&startup_snapshot, &builtin_snapshot, context_snapshots, can_be_rehashed);
|
||||
&startup_snapshot, &builtin_snapshot, &read_only_snapshot,
|
||||
context_snapshots, can_be_rehashed);
|
||||
|
||||
// Delete heap-allocated context snapshot instances.
|
||||
for (const auto context_snapshot : context_snapshots) {
|
||||
|
@ -1472,6 +1472,10 @@ class Isolate : private HiddenFactory {
|
||||
void AddDetachedContext(Handle<Context> context);
|
||||
void CheckDetachedContextsAfterGC();
|
||||
|
||||
std::vector<Object*>* read_only_object_cache() {
|
||||
return &read_only_object_cache_;
|
||||
}
|
||||
|
||||
std::vector<Object*>* partial_snapshot_cache() {
|
||||
return &partial_snapshot_cache_;
|
||||
}
|
||||
@ -1880,6 +1884,7 @@ class Isolate : private HiddenFactory {
|
||||
|
||||
v8::Isolate::UseCounterCallback use_counter_callback_;
|
||||
|
||||
std::vector<Object*> read_only_object_cache_;
|
||||
std::vector<Object*> partial_snapshot_cache_;
|
||||
|
||||
// Used during builtins compilation to build the builtins constants table,
|
||||
|
@ -77,7 +77,8 @@ void BuiltinSerializer::SerializeObject(HeapObject* o, HowToCode how_to_code,
|
||||
// builtin.
|
||||
if (SerializeBuiltinReference(o, how_to_code, where_to_point, skip)) return;
|
||||
|
||||
// Embedded objects are serialized as part of the partial snapshot cache.
|
||||
// Embedded objects are serialized as part of the read-only object and partial
|
||||
// snapshot caches.
|
||||
// Currently we expect to see:
|
||||
// * Code: Jump targets.
|
||||
// * ByteArrays: Relocation infos.
|
||||
@ -87,13 +88,13 @@ void BuiltinSerializer::SerializeObject(HeapObject* o, HowToCode how_to_code,
|
||||
// TODO(6624): Jump targets should never trigger content serialization, it
|
||||
// should always result in a reference instead. Reloc infos and handler tables
|
||||
// should not end up in the partial snapshot cache.
|
||||
if (startup_serializer_->SerializeUsingReadOnlyObjectCache(
|
||||
&sink_, o, how_to_code, where_to_point, skip)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FlushSkip(skip);
|
||||
|
||||
int cache_index = startup_serializer_->PartialSnapshotCacheIndex(o);
|
||||
sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
|
||||
"PartialSnapshotCache");
|
||||
sink_.PutInt(cache_index, "partial_snapshot_cache_index");
|
||||
startup_serializer_->SerializeUsingPartialSnapshotCache(
|
||||
&sink_, o, how_to_code, where_to_point, skip);
|
||||
}
|
||||
|
||||
void BuiltinSerializer::SetBuiltinOffset(int builtin_id, uint32_t offset) {
|
||||
|
@ -473,6 +473,11 @@ bool Deserializer<AllocatorT>::ReadData(MaybeObject** current,
|
||||
SINGLE_CASE(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
|
||||
SINGLE_CASE(kPartialSnapshotCache, kFromCode, kStartOfObject, 0)
|
||||
SINGLE_CASE(kPartialSnapshotCache, kFromCode, kInnerPointer, 0)
|
||||
// Find an object in the partial snapshots cache and write a pointer to it
|
||||
// to the current object.
|
||||
SINGLE_CASE(kReadOnlyObjectCache, kPlain, kStartOfObject, 0)
|
||||
SINGLE_CASE(kReadOnlyObjectCache, kFromCode, kStartOfObject, 0)
|
||||
SINGLE_CASE(kReadOnlyObjectCache, kFromCode, kInnerPointer, 0)
|
||||
// Find an object in the attached references and write a pointer to it to
|
||||
// the current object.
|
||||
SINGLE_CASE(kAttachedReference, kPlain, kStartOfObject, 0)
|
||||
@ -815,6 +820,11 @@ MaybeObject** Deserializer<AllocatorT>::ReadDataCase(
|
||||
new_object = isolate->root(root_index);
|
||||
emit_write_barrier = Heap::InNewSpace(new_object);
|
||||
hot_objects_.Add(HeapObject::cast(new_object));
|
||||
} else if (where == kReadOnlyObjectCache) {
|
||||
int cache_index = source_.GetInt();
|
||||
new_object = isolate->read_only_object_cache()->at(cache_index);
|
||||
DCHECK(!Heap::InNewSpace(new_object));
|
||||
emit_write_barrier = false;
|
||||
} else if (where == kPartialSnapshotCache) {
|
||||
int cache_index = source_.GetInt();
|
||||
new_object = isolate->partial_snapshot_cache()->at(cache_index);
|
||||
|
@ -63,13 +63,14 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
||||
|
||||
if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
|
||||
|
||||
if (ShouldBeInThePartialSnapshotCache(obj)) {
|
||||
FlushSkip(skip);
|
||||
if (startup_serializer_->SerializeUsingReadOnlyObjectCache(
|
||||
&sink_, obj, how_to_code, where_to_point, skip)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cache_index = startup_serializer_->PartialSnapshotCacheIndex(obj);
|
||||
sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
|
||||
"PartialSnapshotCache");
|
||||
sink_.PutInt(cache_index, "partial_snapshot_cache_index");
|
||||
if (ShouldBeInThePartialSnapshotCache(obj)) {
|
||||
startup_serializer_->SerializeUsingPartialSnapshotCache(
|
||||
&sink_, obj, how_to_code, where_to_point, skip);
|
||||
return;
|
||||
}
|
||||
|
||||
|
57
src/snapshot/read-only-deserializer.cc
Normal file
57
src/snapshot/read-only-deserializer.cc
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/snapshot/read-only-deserializer.h"
|
||||
|
||||
#include "src/api.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
#include "src/v8threads.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
void ReadOnlyDeserializer::DeserializeInto(Isolate* isolate) {
|
||||
Initialize(isolate);
|
||||
|
||||
if (!allocator()->ReserveSpace()) {
|
||||
V8::FatalProcessOutOfMemory(isolate, "ReadOnlyDeserializer");
|
||||
}
|
||||
|
||||
// No active threads.
|
||||
DCHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
|
||||
// No active handles.
|
||||
DCHECK(isolate->handle_scope_implementer()->blocks()->empty());
|
||||
// Partial snapshot cache is not yet populated.
|
||||
DCHECK(isolate->read_only_object_cache()->empty());
|
||||
DCHECK(isolate->partial_snapshot_cache()->empty());
|
||||
// Builtins are not yet created.
|
||||
DCHECK(!isolate->builtins()->is_initialized());
|
||||
|
||||
{
|
||||
DisallowHeapAllocation no_gc;
|
||||
|
||||
ReadOnlyRoots(isolate).Iterate(this);
|
||||
|
||||
// Deserialize the Read-only Object Cache.
|
||||
std::vector<Object*>* cache = isolate->read_only_object_cache();
|
||||
for (size_t i = 0;; ++i) {
|
||||
// Extend the array ready to get a value when deserializing.
|
||||
if (cache->size() <= i) cache->push_back(Smi::kZero);
|
||||
// During deserialization, the visitor populates the read-only object
|
||||
// cache and eventually terminates the cache with undefined.
|
||||
VisitRootPointer(Root::kReadOnlyObjectCache, nullptr, &cache->at(i));
|
||||
if (cache->at(i)->IsUndefined(isolate)) break;
|
||||
}
|
||||
DeserializeDeferredObjects();
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyDeserializer::RehashHeap() {
|
||||
DCHECK(FLAG_rehash_snapshot && can_rehash());
|
||||
Rehash();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
34
src/snapshot/read-only-deserializer.h
Normal file
34
src/snapshot/read-only-deserializer.h
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_SNAPSHOT_READ_ONLY_DESERIALIZER_H_
|
||||
#define V8_SNAPSHOT_READ_ONLY_DESERIALIZER_H_
|
||||
|
||||
#include "src/snapshot/deserializer.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Deserializes the read-only blob, creating the read-only roots and the
|
||||
// Read-only object cache used by the other deserializers.
|
||||
class ReadOnlyDeserializer final : public Deserializer<> {
|
||||
public:
|
||||
explicit ReadOnlyDeserializer(const SnapshotData* data)
|
||||
: Deserializer(data, false) {}
|
||||
|
||||
// Deserialize the snapshot into an empty heap.
|
||||
void DeserializeInto(Isolate* isolate);
|
||||
|
||||
private:
|
||||
friend class StartupDeserializer;
|
||||
|
||||
// Rehash after deserializing.
|
||||
void RehashHeap();
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_SNAPSHOT_READ_ONLY_DESERIALIZER_H_
|
102
src/snapshot/read-only-serializer.cc
Normal file
102
src/snapshot/read-only-serializer.cc
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/snapshot/read-only-serializer.h"
|
||||
|
||||
#include "src/api.h"
|
||||
#include "src/code-tracer.h"
|
||||
#include "src/global-handles.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/snapshot/startup-serializer.h"
|
||||
#include "src/v8threads.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
ReadOnlySerializer::ReadOnlySerializer(Isolate* isolate)
|
||||
: RootsSerializer(isolate, RootIndex::kFirstReadOnlyRoot) {
|
||||
STATIC_ASSERT(RootIndex::kFirstReadOnlyRoot == RootIndex::kFirstRoot);
|
||||
}
|
||||
|
||||
ReadOnlySerializer::~ReadOnlySerializer() {
|
||||
OutputStatistics("ReadOnlySerializer");
|
||||
}
|
||||
|
||||
void ReadOnlySerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
||||
WhereToPoint where_to_point,
|
||||
int skip) {
|
||||
CHECK(isolate()->heap()->read_only_space()->Contains(obj));
|
||||
|
||||
if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
|
||||
if (IsRootAndHasBeenSerialized(obj) &&
|
||||
SerializeRoot(obj, how_to_code, where_to_point, skip)) {
|
||||
return;
|
||||
}
|
||||
if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
|
||||
|
||||
FlushSkip(skip);
|
||||
|
||||
CheckRehashability(obj);
|
||||
|
||||
// Object has not yet been serialized. Serialize it here.
|
||||
ObjectSerializer object_serializer(this, obj, &sink_, how_to_code,
|
||||
where_to_point);
|
||||
object_serializer.Serialize();
|
||||
}
|
||||
|
||||
void ReadOnlySerializer::SerializeReadOnlyRoots() {
|
||||
// No active threads.
|
||||
CHECK_NULL(isolate()->thread_manager()->FirstThreadStateInUse());
|
||||
// No active or weak handles.
|
||||
CHECK(isolate()->handle_scope_implementer()->blocks()->empty());
|
||||
|
||||
ReadOnlyRoots(isolate()).Iterate(this);
|
||||
}
|
||||
|
||||
void ReadOnlySerializer::FinalizeSerialization() {
|
||||
// This comes right after serialization of the other snapshots, where we
|
||||
// add entries to the read-only object cache. Add one entry with 'undefined'
|
||||
// to terminate the read-only object cache.
|
||||
Object* undefined = ReadOnlyRoots(isolate()).undefined_value();
|
||||
VisitRootPointer(Root::kReadOnlyObjectCache, nullptr, &undefined);
|
||||
SerializeDeferredObjects();
|
||||
Pad();
|
||||
}
|
||||
|
||||
bool ReadOnlySerializer::MustBeDeferred(HeapObject* object) {
|
||||
if (root_has_been_serialized(RootIndex::kFreeSpaceMap) &&
|
||||
root_has_been_serialized(RootIndex::kOnePointerFillerMap) &&
|
||||
root_has_been_serialized(RootIndex::kTwoPointerFillerMap)) {
|
||||
// All required root objects are serialized, so any aligned objects can
|
||||
// be saved without problems.
|
||||
return false;
|
||||
}
|
||||
// Just defer everything except for Map objects until all required roots are
|
||||
// serialized. Some objects may have special alignment requirements, that may
|
||||
// not be fulfilled during deserialization until few first root objects are
|
||||
// serialized. But we must serialize Map objects since deserializer checks
|
||||
// that these root objects are indeed Maps.
|
||||
return !object->IsMap();
|
||||
}
|
||||
|
||||
bool ReadOnlySerializer::SerializeUsingReadOnlyObjectCache(
|
||||
SnapshotByteSink* sink, HeapObject* obj, HowToCode how_to_code,
|
||||
WhereToPoint where_to_point, int skip) {
|
||||
if (!isolate()->heap()->read_only_space()->Contains(obj)) return false;
|
||||
|
||||
// Get the cache index and serialize it into the read-only snapshot if
|
||||
// necessary.
|
||||
int cache_index = SerializeInObjectCache(obj);
|
||||
|
||||
// Writing out the cache entry into the calling serializer's sink.
|
||||
FlushSkip(sink, skip);
|
||||
sink->Put(kReadOnlyObjectCache + how_to_code + where_to_point,
|
||||
"ReadOnlyObjectCache");
|
||||
sink->PutInt(cache_index, "read_only_object_cache_index");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
46
src/snapshot/read-only-serializer.h
Normal file
46
src/snapshot/read-only-serializer.h
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_SNAPSHOT_READ_ONLY_SERIALIZER_H_
|
||||
#define V8_SNAPSHOT_READ_ONLY_SERIALIZER_H_
|
||||
|
||||
#include "src/snapshot/roots-serializer.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class HeapObject;
|
||||
class SnapshotByteSink;
|
||||
|
||||
class ReadOnlySerializer : public RootsSerializer {
|
||||
public:
|
||||
explicit ReadOnlySerializer(Isolate* isolate);
|
||||
~ReadOnlySerializer() override;
|
||||
|
||||
void SerializeReadOnlyRoots();
|
||||
|
||||
// Completes the serialization of the read-only object cache and serializes
|
||||
// any deferred objects.
|
||||
void FinalizeSerialization();
|
||||
|
||||
// If |obj| can be serialized in the read-only snapshot then add it to the
|
||||
// read-only object cache if not already present and emit a
|
||||
// ReadOnlyObjectCache bytecode into |sink|. Returns whether this was
|
||||
// successful.
|
||||
bool SerializeUsingReadOnlyObjectCache(SnapshotByteSink* sink,
|
||||
HeapObject* obj, HowToCode how_to_code,
|
||||
WhereToPoint where_to_point, int skip);
|
||||
|
||||
private:
|
||||
void SerializeObject(HeapObject* o, HowToCode how_to_code,
|
||||
WhereToPoint where_to_point, int skip) override;
|
||||
bool MustBeDeferred(HeapObject* object) override;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ReadOnlySerializer);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_SNAPSHOT_READ_ONLY_SERIALIZER_H_
|
65
src/snapshot/roots-serializer.cc
Normal file
65
src/snapshot/roots-serializer.cc
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/snapshot/roots-serializer.h"
|
||||
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/objects-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
RootsSerializer::RootsSerializer(Isolate* isolate,
|
||||
RootIndex first_root_to_be_serialized)
|
||||
: Serializer(isolate),
|
||||
first_root_to_be_serialized_(first_root_to_be_serialized),
|
||||
can_be_rehashed_(true) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(first_root_to_be_serialized);
|
||||
++i) {
|
||||
root_has_been_serialized_[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
int RootsSerializer::SerializeInObjectCache(HeapObject* heap_object) {
|
||||
int index;
|
||||
if (!object_cache_index_map_.LookupOrInsert(heap_object, &index)) {
|
||||
// This object is not part of the object cache yet. Add it to the cache so
|
||||
// we can refer to it via cache index from the delegating snapshot.
|
||||
SerializeObject(heap_object, kPlain, kStartOfObject, 0);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void RootsSerializer::Synchronize(VisitorSynchronization::SyncTag tag) {
|
||||
sink_.Put(kSynchronize, "Synchronize");
|
||||
}
|
||||
|
||||
void RootsSerializer::VisitRootPointers(Root root, const char* description,
|
||||
Object** start, Object** end) {
|
||||
RootsTable& roots_table = isolate()->heap()->roots_table();
|
||||
if (start ==
|
||||
roots_table.begin() + static_cast<size_t>(first_root_to_be_serialized_)) {
|
||||
// Serializing the root list needs special handling:
|
||||
// - Only root list elements that have been fully serialized can be
|
||||
// referenced using kRootArray bytecodes.
|
||||
for (Object** current = start; current < end; current++) {
|
||||
SerializeRootObject(*current);
|
||||
size_t root_index = static_cast<size_t>(current - roots_table.begin());
|
||||
root_has_been_serialized_.set(root_index);
|
||||
}
|
||||
} else {
|
||||
Serializer::VisitRootPointers(root, description, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
void RootsSerializer::CheckRehashability(HeapObject* obj) {
|
||||
if (!can_be_rehashed_) return;
|
||||
if (!obj->NeedsRehashing()) return;
|
||||
if (obj->CanBeRehashed()) return;
|
||||
can_be_rehashed_ = false;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
64
src/snapshot/roots-serializer.h
Normal file
64
src/snapshot/roots-serializer.h
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_SNAPSHOT_ROOTS_SERIALIZER_H_
|
||||
#define V8_SNAPSHOT_ROOTS_SERIALIZER_H_
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#include "src/snapshot/serializer.h"
|
||||
#include "src/visitors.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class HeapObject;
|
||||
class Object;
|
||||
class Isolate;
|
||||
enum class RootIndex : uint16_t;
|
||||
|
||||
// Base class for serializer that iterate over roots. Also maintains a cache
|
||||
// that can be used to share non-root objects with other serializers.
|
||||
class RootsSerializer : public Serializer<> {
|
||||
public:
|
||||
// The serializer expects that all roots before |first_root_to_be_serialized|
|
||||
// are already serialized.
|
||||
RootsSerializer(Isolate* isolate, RootIndex first_root_to_be_serialized);
|
||||
|
||||
bool can_be_rehashed() const { return can_be_rehashed_; }
|
||||
bool root_has_been_serialized(RootIndex root_index) const {
|
||||
return root_has_been_serialized_.test(static_cast<size_t>(root_index));
|
||||
}
|
||||
|
||||
bool IsRootAndHasBeenSerialized(HeapObject* obj) const {
|
||||
RootIndex root_index;
|
||||
return root_index_map()->Lookup(obj, &root_index) &&
|
||||
root_has_been_serialized(root_index);
|
||||
}
|
||||
|
||||
protected:
|
||||
void CheckRehashability(HeapObject* obj);
|
||||
|
||||
// Serializes |object| if not previously seen and returns its cache index.
|
||||
int SerializeInObjectCache(HeapObject* object);
|
||||
|
||||
private:
|
||||
void VisitRootPointers(Root root, const char* description, Object** start,
|
||||
Object** end) override;
|
||||
void Synchronize(VisitorSynchronization::SyncTag tag) override;
|
||||
|
||||
const RootIndex first_root_to_be_serialized_;
|
||||
std::bitset<RootsTable::kEntriesCount> root_has_been_serialized_;
|
||||
ObjectCacheIndexMap object_cache_index_map_;
|
||||
// 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(RootsSerializer);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_SNAPSHOT_ROOTS_SERIALIZER_H_
|
@ -123,8 +123,6 @@ class SerializerDeserializer : public RootVisitor {
|
||||
const std::vector<CallHandlerInfo*>& call_handler_infos);
|
||||
|
||||
#define UNUSED_SERIALIZER_BYTE_CODES(V) \
|
||||
V(0x18) \
|
||||
V(0x3d) \
|
||||
V(0x3e) \
|
||||
V(0x3f) \
|
||||
V(0x58) \
|
||||
@ -137,7 +135,6 @@ class SerializerDeserializer : public RootVisitor {
|
||||
V(0x5f) \
|
||||
V(0x67) \
|
||||
V(0x76) \
|
||||
V(0x78) \
|
||||
V(0x79) \
|
||||
V(0x7a) \
|
||||
V(0x7b) \
|
||||
@ -169,6 +166,8 @@ class SerializerDeserializer : public RootVisitor {
|
||||
kRootArray = 0x16,
|
||||
// 0x17 Object provided in the attached list.
|
||||
kAttachedReference = 0x17,
|
||||
// 0x18 Object in the read-only object cache.
|
||||
kReadOnlyObjectCache = 0x18,
|
||||
|
||||
// 0x0f Misc, see below (incl. 0x2f, 0x4f, 0x6f).
|
||||
// 0x18..0x1f Misc, see below (incl. 0x38..0x3f, 0x58..0x5f, 0x78..0x7f).
|
||||
@ -225,15 +224,15 @@ class SerializerDeserializer : public RootVisitor {
|
||||
// Used for embedder-provided serialization data for embedder fields.
|
||||
static const int kEmbedderFieldsData = 0x1f;
|
||||
|
||||
// Used to encode external referenced provided through the API.
|
||||
static const int kApiReference = 0x38;
|
||||
|
||||
static const int kVariableRawCode = 0x39;
|
||||
static const int kVariableRawData = 0x3a;
|
||||
|
||||
static const int kInternalReference = 0x3b;
|
||||
static const int kInternalReferenceEncoded = 0x3c;
|
||||
|
||||
// Used to encode external references provided through the API.
|
||||
static const int kApiReference = 0x3d;
|
||||
|
||||
// In-place weak references
|
||||
static const int kWeakPrefix = 0x7e;
|
||||
|
||||
|
@ -127,6 +127,33 @@ class CodeAddressMap : public CodeEventLogger {
|
||||
NameMap address_to_name_map_;
|
||||
};
|
||||
|
||||
class ObjectCacheIndexMap {
|
||||
public:
|
||||
ObjectCacheIndexMap() : map_(), next_index_(0) {}
|
||||
|
||||
// If |obj| is in the map, immediately return true. Otherwise add it to the
|
||||
// map and return false. In either case set |*index_out| to the index
|
||||
// associated with the map.
|
||||
bool LookupOrInsert(HeapObject* obj, int* index_out) {
|
||||
Maybe<uint32_t> maybe_index = map_.Get(obj);
|
||||
if (maybe_index.IsJust()) {
|
||||
*index_out = maybe_index.FromJust();
|
||||
return true;
|
||||
}
|
||||
*index_out = next_index_;
|
||||
map_.Set(obj, next_index_++);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
DisallowHeapAllocation no_allocation_;
|
||||
|
||||
HeapObjectToIndexHashMap map_;
|
||||
int next_index_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObjectCacheIndexMap);
|
||||
};
|
||||
|
||||
template <class AllocatorT = DefaultSerializerAllocator>
|
||||
class Serializer : public SerializerDeserializer {
|
||||
public:
|
||||
@ -202,13 +229,15 @@ class Serializer : public SerializerDeserializer {
|
||||
// Returns true if the given heap object is a bytecode handler code object.
|
||||
bool ObjectIsBytecodeHandler(HeapObject* obj) const;
|
||||
|
||||
inline void FlushSkip(int skip) {
|
||||
static inline void FlushSkip(SnapshotByteSink* sink, int skip) {
|
||||
if (skip != 0) {
|
||||
sink_.Put(kSkip, "SkipFromSerializeObject");
|
||||
sink_.PutInt(skip, "SkipDistanceFromSerializeObject");
|
||||
sink->Put(kSkip, "SkipFromSerializeObject");
|
||||
sink->PutInt(skip, "SkipDistanceFromSerializeObject");
|
||||
}
|
||||
}
|
||||
|
||||
inline void FlushSkip(int skip) { FlushSkip(&sink_, skip); }
|
||||
|
||||
ExternalReferenceEncoder::Value EncodeExternalReference(Address addr) {
|
||||
return external_reference_encoder_.Encode(addr);
|
||||
}
|
||||
|
@ -49,8 +49,10 @@ bool Snapshot::Initialize(Isolate* isolate) {
|
||||
SnapshotData startup_snapshot_data(startup_data);
|
||||
Vector<const byte> builtin_data = ExtractBuiltinData(blob);
|
||||
BuiltinSnapshotData builtin_snapshot_data(builtin_data);
|
||||
StartupDeserializer deserializer(&startup_snapshot_data,
|
||||
&builtin_snapshot_data);
|
||||
Vector<const byte> read_only_data = ExtractReadOnlyData(blob);
|
||||
SnapshotData read_only_snapshot_data(read_only_data);
|
||||
StartupDeserializer deserializer(
|
||||
&startup_snapshot_data, &builtin_snapshot_data, &read_only_snapshot_data);
|
||||
deserializer.SetRehashability(ExtractRehashability(blob));
|
||||
bool success = isolate->Init(&deserializer);
|
||||
if (FLAG_profile_deserialization) {
|
||||
@ -174,11 +176,15 @@ Code* Snapshot::EnsureBuiltinIsDeserialized(Isolate* isolate,
|
||||
}
|
||||
|
||||
void ProfileDeserialization(
|
||||
const SnapshotData* read_only_snapshot,
|
||||
const SnapshotData* startup_snapshot, const SnapshotData* builtin_snapshot,
|
||||
const std::vector<SnapshotData*>& context_snapshots) {
|
||||
if (FLAG_profile_deserialization) {
|
||||
int startup_total = 0;
|
||||
PrintF("Deserialization will reserve:\n");
|
||||
for (const auto& reservation : read_only_snapshot->Reservations()) {
|
||||
startup_total += reservation.chunk_size();
|
||||
}
|
||||
for (const auto& reservation : startup_snapshot->Reservations()) {
|
||||
startup_total += reservation.chunk_size();
|
||||
}
|
||||
@ -199,6 +205,7 @@ void ProfileDeserialization(
|
||||
v8::StartupData Snapshot::CreateSnapshotBlob(
|
||||
const SnapshotData* startup_snapshot,
|
||||
const BuiltinSnapshotData* builtin_snapshot,
|
||||
const SnapshotData* read_only_snapshot,
|
||||
const std::vector<SnapshotData*>& context_snapshots, bool can_be_rehashed) {
|
||||
uint32_t num_contexts = static_cast<uint32_t>(context_snapshots.size());
|
||||
uint32_t startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
|
||||
@ -208,12 +215,15 @@ v8::StartupData Snapshot::CreateSnapshotBlob(
|
||||
DCHECK(IsAligned(total_length, kPointerAlignment));
|
||||
total_length += static_cast<uint32_t>(builtin_snapshot->RawData().length());
|
||||
DCHECK(IsAligned(total_length, kPointerAlignment));
|
||||
total_length += static_cast<uint32_t>(read_only_snapshot->RawData().length());
|
||||
DCHECK(IsAligned(total_length, kPointerAlignment));
|
||||
for (const auto context_snapshot : context_snapshots) {
|
||||
total_length += static_cast<uint32_t>(context_snapshot->RawData().length());
|
||||
DCHECK(IsAligned(total_length, kPointerAlignment));
|
||||
}
|
||||
|
||||
ProfileDeserialization(startup_snapshot, builtin_snapshot, context_snapshots);
|
||||
ProfileDeserialization(read_only_snapshot, startup_snapshot, builtin_snapshot,
|
||||
context_snapshots);
|
||||
|
||||
char* data = new char[total_length];
|
||||
// Zero out pre-payload data. Part of that is only used for padding.
|
||||
@ -252,6 +262,18 @@ v8::StartupData Snapshot::CreateSnapshotBlob(
|
||||
}
|
||||
payload_offset += payload_length;
|
||||
|
||||
// Read-only.
|
||||
SetHeaderValue(data, kReadOnlyOffsetOffset, payload_offset);
|
||||
payload_length = read_only_snapshot->RawData().length();
|
||||
CopyBytes(
|
||||
data + payload_offset,
|
||||
reinterpret_cast<const char*>(read_only_snapshot->RawData().start()),
|
||||
payload_length);
|
||||
if (FLAG_profile_deserialization) {
|
||||
PrintF("%10d bytes for read-only\n", payload_length);
|
||||
}
|
||||
payload_offset += payload_length;
|
||||
|
||||
// Partial snapshots (context-specific data).
|
||||
for (uint32_t i = 0; i < num_contexts; i++) {
|
||||
SetHeaderValue(data, ContextSnapshotOffsetOffset(i), payload_offset);
|
||||
@ -563,33 +585,38 @@ bool Snapshot::ExtractRehashability(const v8::StartupData* data) {
|
||||
return GetHeaderValue(data, kRehashabilityOffset) != 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
Vector<const byte> ExtractData(const v8::StartupData* snapshot,
|
||||
uint32_t start_offset, uint32_t end_offset) {
|
||||
CHECK_LT(start_offset, end_offset);
|
||||
CHECK_LT(end_offset, snapshot->raw_size);
|
||||
uint32_t length = end_offset - start_offset;
|
||||
const byte* data =
|
||||
reinterpret_cast<const byte*>(snapshot->data + start_offset);
|
||||
return Vector<const byte>(data, length);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
|
||||
DCHECK(SnapshotIsValid(data));
|
||||
|
||||
uint32_t num_contexts = ExtractNumContexts(data);
|
||||
uint32_t startup_offset = StartupSnapshotOffset(num_contexts);
|
||||
CHECK_LT(startup_offset, data->raw_size);
|
||||
uint32_t builtin_offset = GetHeaderValue(data, kBuiltinOffsetOffset);
|
||||
CHECK_LT(builtin_offset, data->raw_size);
|
||||
CHECK_GT(builtin_offset, startup_offset);
|
||||
uint32_t startup_length = builtin_offset - startup_offset;
|
||||
const byte* startup_data =
|
||||
reinterpret_cast<const byte*>(data->data + startup_offset);
|
||||
return Vector<const byte>(startup_data, startup_length);
|
||||
return ExtractData(data, StartupSnapshotOffset(num_contexts),
|
||||
GetHeaderValue(data, kBuiltinOffsetOffset));
|
||||
}
|
||||
|
||||
Vector<const byte> Snapshot::ExtractBuiltinData(const v8::StartupData* data) {
|
||||
DCHECK(SnapshotIsValid(data));
|
||||
|
||||
uint32_t from_offset = GetHeaderValue(data, kBuiltinOffsetOffset);
|
||||
CHECK_LT(from_offset, data->raw_size);
|
||||
return ExtractData(data, GetHeaderValue(data, kBuiltinOffsetOffset),
|
||||
GetHeaderValue(data, kReadOnlyOffsetOffset));
|
||||
}
|
||||
|
||||
uint32_t to_offset = GetHeaderValue(data, ContextSnapshotOffsetOffset(0));
|
||||
CHECK_LT(to_offset, data->raw_size);
|
||||
Vector<const byte> Snapshot::ExtractReadOnlyData(const v8::StartupData* data) {
|
||||
DCHECK(SnapshotIsValid(data));
|
||||
|
||||
CHECK_GT(to_offset, from_offset);
|
||||
uint32_t length = to_offset - from_offset;
|
||||
const byte* builtin_data =
|
||||
reinterpret_cast<const byte*>(data->data + from_offset);
|
||||
return Vector<const byte>(builtin_data, length);
|
||||
return ExtractData(data, GetHeaderValue(data, kReadOnlyOffsetOffset),
|
||||
GetHeaderValue(data, ContextSnapshotOffsetOffset(0)));
|
||||
}
|
||||
|
||||
Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
|
||||
|
@ -190,6 +190,7 @@ class Snapshot : public AllStatic {
|
||||
static v8::StartupData CreateSnapshotBlob(
|
||||
const SnapshotData* startup_snapshot,
|
||||
const BuiltinSnapshotData* builtin_snapshot,
|
||||
const SnapshotData* read_only_snapshot,
|
||||
const std::vector<SnapshotData*>& context_snapshots,
|
||||
bool can_be_rehashed);
|
||||
|
||||
@ -203,6 +204,7 @@ class Snapshot : public AllStatic {
|
||||
uint32_t index);
|
||||
static bool ExtractRehashability(const v8::StartupData* data);
|
||||
static Vector<const byte> ExtractStartupData(const v8::StartupData* data);
|
||||
static Vector<const byte> ExtractReadOnlyData(const v8::StartupData* data);
|
||||
static Vector<const byte> ExtractBuiltinData(const v8::StartupData* data);
|
||||
static Vector<const byte> ExtractContextData(const v8::StartupData* data,
|
||||
uint32_t index);
|
||||
@ -224,12 +226,14 @@ class Snapshot : public AllStatic {
|
||||
// [3] checksum part B
|
||||
// [4] (128 bytes) version string
|
||||
// [5] offset to builtins
|
||||
// [6] offset to context 0
|
||||
// [7] offset to context 1
|
||||
// [6] offset to readonly
|
||||
// [7] offset to context 0
|
||||
// [8] offset to context 1
|
||||
// ...
|
||||
// ... offset to context N - 1
|
||||
// ... startup snapshot data
|
||||
// ... builtin snapshot data
|
||||
// ... read-only snapshot data
|
||||
// ... context 0 snapshot data
|
||||
// ... context 1 snapshot data
|
||||
|
||||
@ -246,8 +250,10 @@ class Snapshot : public AllStatic {
|
||||
static const uint32_t kVersionStringLength = 64;
|
||||
static const uint32_t kBuiltinOffsetOffset =
|
||||
kVersionStringOffset + kVersionStringLength;
|
||||
static const uint32_t kFirstContextOffsetOffset =
|
||||
static const uint32_t kReadOnlyOffsetOffset =
|
||||
kBuiltinOffsetOffset + kUInt32Size;
|
||||
static const uint32_t kFirstContextOffsetOffset =
|
||||
kReadOnlyOffsetOffset + kUInt32Size;
|
||||
|
||||
static Vector<const byte> ChecksummedContent(const v8::StartupData* data) {
|
||||
const uint32_t kChecksumStart = kVersionStringOffset;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/code-tracer.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/snapshot/builtin-deserializer.h"
|
||||
#include "src/snapshot/read-only-deserializer.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -18,6 +19,9 @@ namespace internal {
|
||||
void StartupDeserializer::DeserializeInto(Isolate* isolate) {
|
||||
Initialize(isolate);
|
||||
|
||||
ReadOnlyDeserializer read_only_deserializer(read_only_data_);
|
||||
read_only_deserializer.SetRehashability(can_rehash());
|
||||
read_only_deserializer.DeserializeInto(isolate);
|
||||
BuiltinDeserializer builtin_deserializer(isolate, builtin_data_);
|
||||
|
||||
if (!DefaultDeserializerAllocator::ReserveSpace(this,
|
||||
@ -37,7 +41,6 @@ void StartupDeserializer::DeserializeInto(Isolate* isolate) {
|
||||
{
|
||||
DisallowHeapAllocation no_gc;
|
||||
isolate->heap()->IterateSmiRoots(this);
|
||||
ReadOnlyRoots(isolate).Iterate(this);
|
||||
isolate->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
|
||||
isolate->heap()->RepairFreeListsAfterDeserialization();
|
||||
isolate->heap()->IterateWeakRoots(this, VISIT_FOR_SERIALIZATION);
|
||||
@ -74,7 +77,11 @@ void StartupDeserializer::DeserializeInto(Isolate* isolate) {
|
||||
// to display the builtin names.
|
||||
PrintDisassembledCodeObjects();
|
||||
|
||||
if (FLAG_rehash_snapshot && can_rehash()) RehashHeap();
|
||||
if (FLAG_rehash_snapshot && can_rehash()) {
|
||||
isolate->heap()->InitializeHashSeed();
|
||||
read_only_deserializer.RehashHeap();
|
||||
Rehash();
|
||||
}
|
||||
}
|
||||
|
||||
void StartupDeserializer::FlushICacheForNewIsolate() {
|
||||
@ -111,11 +118,5 @@ void StartupDeserializer::PrintDisassembledCodeObjects() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void StartupDeserializer::RehashHeap() {
|
||||
DCHECK(FLAG_rehash_snapshot && can_rehash());
|
||||
isolate()->heap()->InitializeHashSeed();
|
||||
Rehash();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -15,8 +15,11 @@ namespace internal {
|
||||
class StartupDeserializer final : public Deserializer<> {
|
||||
public:
|
||||
StartupDeserializer(const SnapshotData* startup_data,
|
||||
const BuiltinSnapshotData* builtin_data)
|
||||
: Deserializer(startup_data, false), builtin_data_(builtin_data) {}
|
||||
const BuiltinSnapshotData* builtin_data,
|
||||
const SnapshotData* read_only_data)
|
||||
: Deserializer(startup_data, false),
|
||||
read_only_data_(read_only_data),
|
||||
builtin_data_(builtin_data) {}
|
||||
|
||||
// Deserialize the snapshot into an empty heap.
|
||||
void DeserializeInto(Isolate* isolate);
|
||||
@ -25,9 +28,7 @@ class StartupDeserializer final : public Deserializer<> {
|
||||
void FlushICacheForNewIsolate();
|
||||
void PrintDisassembledCodeObjects();
|
||||
|
||||
// Rehash after deserializing an isolate.
|
||||
void RehashHeap();
|
||||
|
||||
const SnapshotData* read_only_data_;
|
||||
const BuiltinSnapshotData* builtin_data_;
|
||||
};
|
||||
|
||||
|
@ -8,13 +8,16 @@
|
||||
#include "src/code-tracer.h"
|
||||
#include "src/global-handles.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/snapshot/read-only-serializer.h"
|
||||
#include "src/v8threads.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
StartupSerializer::StartupSerializer(Isolate* isolate)
|
||||
: Serializer(isolate), can_be_rehashed_(true) {
|
||||
StartupSerializer::StartupSerializer(Isolate* isolate,
|
||||
ReadOnlySerializer* read_only_serializer)
|
||||
: RootsSerializer(isolate, RootIndex::kFirstStrongRoot),
|
||||
read_only_serializer_(read_only_serializer) {
|
||||
InitializeCodeAddressMap();
|
||||
}
|
||||
|
||||
@ -36,6 +39,9 @@ void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
||||
if (IsRootAndHasBeenSerialized(obj) &&
|
||||
SerializeRoot(obj, how_to_code, where_to_point, skip))
|
||||
return;
|
||||
if (SerializeUsingReadOnlyObjectCache(&sink_, obj, how_to_code,
|
||||
where_to_point, skip))
|
||||
return;
|
||||
if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
|
||||
|
||||
FlushSkip(skip);
|
||||
@ -71,6 +77,7 @@ void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
||||
CheckRehashability(obj);
|
||||
|
||||
// Object has not yet been serialized. Serialize it here.
|
||||
DCHECK(!isolate()->heap()->read_only_space()->Contains(obj));
|
||||
ObjectSerializer object_serializer(this, obj, &sink_, how_to_code,
|
||||
where_to_point);
|
||||
object_serializer.Serialize();
|
||||
@ -87,22 +94,6 @@ void StartupSerializer::SerializeWeakReferencesAndDeferred() {
|
||||
Pad();
|
||||
}
|
||||
|
||||
int StartupSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
|
||||
int index;
|
||||
if (!partial_cache_index_map_.LookupOrInsert(heap_object, &index)) {
|
||||
// This object is not part of the partial snapshot cache yet. Add it to the
|
||||
// startup snapshot so we can refer to it via partial snapshot index from
|
||||
// the partial snapshot.
|
||||
VisitRootPointer(Root::kPartialSnapshotCache, nullptr,
|
||||
reinterpret_cast<Object**>(&heap_object));
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void StartupSerializer::Synchronize(VisitorSynchronization::SyncTag tag) {
|
||||
sink_.Put(kSynchronize, "Synchronize");
|
||||
}
|
||||
|
||||
void StartupSerializer::SerializeStrongReferences() {
|
||||
Isolate* isolate = this->isolate();
|
||||
// No active threads.
|
||||
@ -117,49 +108,9 @@ void StartupSerializer::SerializeStrongReferences() {
|
||||
isolate->heap()->IterateSmiRoots(this);
|
||||
isolate->heap()->SetStackLimits();
|
||||
// First visit immortal immovables to make sure they end up in the first page.
|
||||
ReadOnlyRoots(isolate).Iterate(this);
|
||||
isolate->heap()->IterateStrongRoots(this, VISIT_FOR_SERIALIZATION);
|
||||
}
|
||||
|
||||
void StartupSerializer::VisitRootPointers(Root root, const char* description,
|
||||
Object** start, Object** end) {
|
||||
if (start == isolate()->roots_array_start()) {
|
||||
// Serializing the root list needs special handling:
|
||||
// - Only root list elements that have been fully serialized can be
|
||||
// referenced using kRootArray bytecodes.
|
||||
for (Object** current = start; current < end; current++) {
|
||||
SerializeRootObject(*current);
|
||||
size_t root_index = static_cast<size_t>(current - start);
|
||||
root_has_been_serialized_.set(root_index);
|
||||
}
|
||||
} else {
|
||||
Serializer::VisitRootPointers(root, description, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
void StartupSerializer::CheckRehashability(HeapObject* obj) {
|
||||
if (!can_be_rehashed_) return;
|
||||
if (!obj->NeedsRehashing()) return;
|
||||
if (obj->CanBeRehashed()) return;
|
||||
can_be_rehashed_ = false;
|
||||
}
|
||||
|
||||
bool StartupSerializer::MustBeDeferred(HeapObject* object) {
|
||||
if (root_has_been_serialized(RootIndex::kFreeSpaceMap) &&
|
||||
root_has_been_serialized(RootIndex::kOnePointerFillerMap) &&
|
||||
root_has_been_serialized(RootIndex::kTwoPointerFillerMap)) {
|
||||
// All required root objects are serialized, so any aligned objects can
|
||||
// be saved without problems.
|
||||
return false;
|
||||
}
|
||||
// Just defer everything except of Map objects until all required roots are
|
||||
// serialized. Some objects may have special alignment requirements, that may
|
||||
// not be fulfilled during deserialization until few first root objects are
|
||||
// serialized. But we must serialize Map objects since deserializer checks
|
||||
// that these root objects are indeed Maps.
|
||||
return !object->IsMap();
|
||||
}
|
||||
|
||||
SerializedHandleChecker::SerializedHandleChecker(
|
||||
Isolate* isolate, std::vector<Context*>* contexts)
|
||||
: isolate_(isolate) {
|
||||
@ -169,6 +120,24 @@ SerializedHandleChecker::SerializedHandleChecker(
|
||||
}
|
||||
}
|
||||
|
||||
bool StartupSerializer::SerializeUsingReadOnlyObjectCache(
|
||||
SnapshotByteSink* sink, HeapObject* obj, HowToCode how_to_code,
|
||||
WhereToPoint where_to_point, int skip) {
|
||||
return read_only_serializer_->SerializeUsingReadOnlyObjectCache(
|
||||
sink, obj, how_to_code, where_to_point, skip);
|
||||
}
|
||||
|
||||
void StartupSerializer::SerializeUsingPartialSnapshotCache(
|
||||
SnapshotByteSink* sink, HeapObject* obj, HowToCode how_to_code,
|
||||
WhereToPoint where_to_point, int skip) {
|
||||
FlushSkip(sink, skip);
|
||||
|
||||
int cache_index = SerializeInObjectCache(obj);
|
||||
sink->Put(kPartialSnapshotCache + how_to_code + where_to_point,
|
||||
"PartialSnapshotCache");
|
||||
sink->PutInt(cache_index, "partial_snapshot_cache_index");
|
||||
}
|
||||
|
||||
void SerializedHandleChecker::AddToSet(FixedArray* serialized) {
|
||||
int length = serialized->length();
|
||||
for (int i = 0; i < length; i++) serialized_.insert(serialized->get(i));
|
||||
|
@ -5,16 +5,20 @@
|
||||
#ifndef V8_SNAPSHOT_STARTUP_SERIALIZER_H_
|
||||
#define V8_SNAPSHOT_STARTUP_SERIALIZER_H_
|
||||
|
||||
#include <bitset>
|
||||
#include "include/v8.h"
|
||||
#include "src/snapshot/serializer.h"
|
||||
#include <unordered_set>
|
||||
|
||||
#include "src/snapshot/roots-serializer.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class StartupSerializer : public Serializer<> {
|
||||
class HeapObject;
|
||||
class SnapshotByteSink;
|
||||
class ReadOnlySerializer;
|
||||
|
||||
class StartupSerializer : public RootsSerializer {
|
||||
public:
|
||||
explicit StartupSerializer(Isolate* isolate);
|
||||
StartupSerializer(Isolate* isolate, ReadOnlySerializer* read_only_serializer);
|
||||
~StartupSerializer() override;
|
||||
|
||||
// Serialize the current state of the heap. The order is:
|
||||
@ -25,63 +29,29 @@ class StartupSerializer : public Serializer<> {
|
||||
void SerializeStrongReferences();
|
||||
void SerializeWeakReferencesAndDeferred();
|
||||
|
||||
int PartialSnapshotCacheIndex(HeapObject* o);
|
||||
// If |obj| can be serialized in the read-only snapshot then add it to the
|
||||
// read-only object cache if not already present and emits a
|
||||
// ReadOnlyObjectCache bytecode into |sink|. Returns whether this was
|
||||
// successful.
|
||||
bool SerializeUsingReadOnlyObjectCache(SnapshotByteSink* sink,
|
||||
HeapObject* obj, HowToCode how_to_code,
|
||||
WhereToPoint where_to_point, int skip);
|
||||
|
||||
bool can_be_rehashed() const { return can_be_rehashed_; }
|
||||
bool root_has_been_serialized(RootIndex root_index) const {
|
||||
return root_has_been_serialized_.test(static_cast<size_t>(root_index));
|
||||
}
|
||||
|
||||
bool IsRootAndHasBeenSerialized(HeapObject* obj) const {
|
||||
RootIndex root_index;
|
||||
return root_index_map()->Lookup(obj, &root_index) &&
|
||||
root_has_been_serialized(root_index);
|
||||
}
|
||||
// Adds |obj| to the partial snapshot object cache if not already present and
|
||||
// emits a PartialSnapshotCache bytecode into |sink|.
|
||||
void SerializeUsingPartialSnapshotCache(SnapshotByteSink* sink,
|
||||
HeapObject* obj,
|
||||
HowToCode how_to_code,
|
||||
WhereToPoint where_to_point,
|
||||
int skip);
|
||||
|
||||
private:
|
||||
class PartialCacheIndexMap {
|
||||
public:
|
||||
PartialCacheIndexMap() : map_(), next_index_(0) {}
|
||||
|
||||
// Lookup object in the map. Return its index if found, or create
|
||||
// a new entry with new_index as value, and return kInvalidIndex.
|
||||
bool LookupOrInsert(HeapObject* obj, int* index_out) {
|
||||
Maybe<uint32_t> maybe_index = map_.Get(obj);
|
||||
if (maybe_index.IsJust()) {
|
||||
*index_out = maybe_index.FromJust();
|
||||
return true;
|
||||
}
|
||||
*index_out = next_index_;
|
||||
map_.Set(obj, next_index_++);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_HEAP_ALLOCATION(no_allocation_);
|
||||
HeapObjectToIndexHashMap map_;
|
||||
int next_index_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PartialCacheIndexMap);
|
||||
};
|
||||
|
||||
// The StartupSerializer has to serialize the root array, which is slightly
|
||||
// different.
|
||||
void VisitRootPointers(Root root, const char* description, Object** start,
|
||||
Object** end) override;
|
||||
void SerializeObject(HeapObject* o, HowToCode how_to_code,
|
||||
WhereToPoint where_to_point, int skip) override;
|
||||
void Synchronize(VisitorSynchronization::SyncTag tag) override;
|
||||
bool MustBeDeferred(HeapObject* object) override;
|
||||
|
||||
void CheckRehashability(HeapObject* obj);
|
||||
|
||||
std::bitset<RootsTable::kEntriesCount> root_has_been_serialized_;
|
||||
PartialCacheIndexMap partial_cache_index_map_;
|
||||
ReadOnlySerializer* read_only_serializer_;
|
||||
std::vector<AccessorInfo*> accessor_infos_;
|
||||
std::vector<CallHandlerInfo*> call_handler_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);
|
||||
};
|
||||
|
@ -35,6 +35,7 @@ class Object;
|
||||
V(kExtensions, "(Extensions)") \
|
||||
V(kCodeFlusher, "(Code flusher)") \
|
||||
V(kPartialSnapshotCache, "(Partial snapshot cache)") \
|
||||
V(kReadOnlyObjectCache, "(Read-only object cache)") \
|
||||
V(kWeakCollections, "(Weak collections)") \
|
||||
V(kWrapperTracing, "(Wrapper tracing)") \
|
||||
V(kUnknown, "(Unknown)")
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "src/snapshot/natives.h"
|
||||
#include "src/snapshot/partial-deserializer.h"
|
||||
#include "src/snapshot/partial-serializer.h"
|
||||
#include "src/snapshot/read-only-serializer.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
#include "src/snapshot/startup-deserializer.h"
|
||||
#include "src/snapshot/startup-serializer.h"
|
||||
@ -129,15 +130,17 @@ static Vector<const byte> WritePayload(const Vector<const byte>& payload) {
|
||||
return Vector<const byte>(const_cast<const byte*>(blob), length);
|
||||
}
|
||||
|
||||
// A convenience struct to simplify management of the two blobs required to
|
||||
// A convenience struct to simplify management of the blobs required to
|
||||
// deserialize an isolate.
|
||||
struct StartupBlobs {
|
||||
Vector<const byte> startup;
|
||||
Vector<const byte> builtin;
|
||||
Vector<const byte> read_only;
|
||||
|
||||
void Dispose() {
|
||||
startup.Dispose();
|
||||
builtin.Dispose();
|
||||
read_only.Dispose();
|
||||
}
|
||||
};
|
||||
|
||||
@ -237,17 +240,24 @@ static StartupBlobs Serialize(v8::Isolate* isolate) {
|
||||
Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
|
||||
internal_isolate->heap()->CollectAllAvailableGarbage(
|
||||
i::GarbageCollectionReason::kTesting);
|
||||
StartupSerializer ser(internal_isolate);
|
||||
|
||||
ReadOnlySerializer read_only_serializer(internal_isolate);
|
||||
read_only_serializer.SerializeReadOnlyRoots();
|
||||
|
||||
StartupSerializer ser(internal_isolate, &read_only_serializer);
|
||||
ser.SerializeStrongReferences();
|
||||
|
||||
i::BuiltinSerializer builtin_serializer(internal_isolate, &ser);
|
||||
builtin_serializer.SerializeBuiltinsAndHandlers();
|
||||
|
||||
ser.SerializeWeakReferencesAndDeferred();
|
||||
read_only_serializer.FinalizeSerialization();
|
||||
SnapshotData startup_snapshot(&ser);
|
||||
SnapshotData read_only_snapshot(&read_only_serializer);
|
||||
BuiltinSnapshotData builtin_snapshot(&builtin_serializer);
|
||||
return {WritePayload(startup_snapshot.RawData()),
|
||||
WritePayload(builtin_snapshot.RawData())};
|
||||
WritePayload(builtin_snapshot.RawData()),
|
||||
WritePayload(read_only_snapshot.RawData())};
|
||||
}
|
||||
|
||||
|
||||
@ -271,8 +281,10 @@ v8::Isolate* InitializeFromBlob(StartupBlobs& blobs) {
|
||||
v8::Isolate* v8_isolate = nullptr;
|
||||
{
|
||||
SnapshotData startup_snapshot(blobs.startup);
|
||||
SnapshotData read_only_snapshot(blobs.read_only);
|
||||
BuiltinSnapshotData builtin_snapshot(blobs.builtin);
|
||||
StartupDeserializer deserializer(&startup_snapshot, &builtin_snapshot);
|
||||
StartupDeserializer deserializer(&startup_snapshot, &builtin_snapshot,
|
||||
&read_only_snapshot);
|
||||
const bool kEnableSerializer = false;
|
||||
const bool kGenerateHeap = false;
|
||||
TestIsolate* isolate = new TestIsolate(kEnableSerializer, kGenerateHeap);
|
||||
@ -484,6 +496,7 @@ UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) {
|
||||
|
||||
static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
|
||||
Vector<const byte>* builtin_blob_out,
|
||||
Vector<const byte>* read_only_blob_out,
|
||||
Vector<const byte>* partial_blob_out) {
|
||||
v8::Isolate* v8_isolate = TestIsolate::NewInitialized();
|
||||
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
|
||||
@ -515,8 +528,12 @@ static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
|
||||
|
||||
env.Reset();
|
||||
|
||||
SnapshotByteSink read_only_sink;
|
||||
ReadOnlySerializer read_only_serializer(isolate);
|
||||
read_only_serializer.SerializeReadOnlyRoots();
|
||||
|
||||
SnapshotByteSink startup_sink;
|
||||
StartupSerializer startup_serializer(isolate);
|
||||
StartupSerializer startup_serializer(isolate, &read_only_serializer);
|
||||
startup_serializer.SerializeStrongReferences();
|
||||
|
||||
SnapshotByteSink partial_sink;
|
||||
@ -529,6 +546,9 @@ static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
|
||||
|
||||
startup_serializer.SerializeWeakReferencesAndDeferred();
|
||||
|
||||
read_only_serializer.FinalizeSerialization();
|
||||
|
||||
SnapshotData read_only_snapshot(&read_only_serializer);
|
||||
SnapshotData startup_snapshot(&startup_serializer);
|
||||
BuiltinSnapshotData builtin_snapshot(&builtin_serializer);
|
||||
SnapshotData partial_snapshot(&partial_serializer);
|
||||
@ -536,6 +556,7 @@ static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
|
||||
*partial_blob_out = WritePayload(partial_snapshot.RawData());
|
||||
*builtin_blob_out = WritePayload(builtin_snapshot.RawData());
|
||||
*startup_blob_out = WritePayload(startup_snapshot.RawData());
|
||||
*read_only_blob_out = WritePayload(read_only_snapshot.RawData());
|
||||
}
|
||||
v8_isolate->Dispose();
|
||||
}
|
||||
@ -545,10 +566,12 @@ UNINITIALIZED_TEST(PartialSerializerContext) {
|
||||
DisableAlwaysOpt();
|
||||
Vector<const byte> startup_blob;
|
||||
Vector<const byte> builtin_blob;
|
||||
Vector<const byte> read_only_blob;
|
||||
Vector<const byte> partial_blob;
|
||||
PartiallySerializeContext(&startup_blob, &builtin_blob, &partial_blob);
|
||||
PartiallySerializeContext(&startup_blob, &builtin_blob, &read_only_blob,
|
||||
&partial_blob);
|
||||
|
||||
StartupBlobs blobs = {startup_blob, builtin_blob};
|
||||
StartupBlobs blobs = {startup_blob, builtin_blob, read_only_blob};
|
||||
v8::Isolate* v8_isolate = InitializeFromBlob(blobs);
|
||||
CHECK(v8_isolate);
|
||||
{
|
||||
@ -588,6 +611,7 @@ UNINITIALIZED_TEST(PartialSerializerContext) {
|
||||
|
||||
static void PartiallySerializeCustomContext(
|
||||
Vector<const byte>* startup_blob_out, Vector<const byte>* builtin_blob_out,
|
||||
Vector<const byte>* read_only_blob_out,
|
||||
Vector<const byte>* partial_blob_out) {
|
||||
v8::Isolate* v8_isolate = TestIsolate::NewInitialized();
|
||||
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
|
||||
@ -639,8 +663,12 @@ static void PartiallySerializeCustomContext(
|
||||
|
||||
env.Reset();
|
||||
|
||||
SnapshotByteSink read_only_sink;
|
||||
ReadOnlySerializer read_only_serializer(isolate);
|
||||
read_only_serializer.SerializeReadOnlyRoots();
|
||||
|
||||
SnapshotByteSink startup_sink;
|
||||
StartupSerializer startup_serializer(isolate);
|
||||
StartupSerializer startup_serializer(isolate, &read_only_serializer);
|
||||
startup_serializer.SerializeStrongReferences();
|
||||
|
||||
SnapshotByteSink partial_sink;
|
||||
@ -653,6 +681,9 @@ static void PartiallySerializeCustomContext(
|
||||
|
||||
startup_serializer.SerializeWeakReferencesAndDeferred();
|
||||
|
||||
read_only_serializer.FinalizeSerialization();
|
||||
|
||||
SnapshotData read_only_snapshot(&read_only_serializer);
|
||||
SnapshotData startup_snapshot(&startup_serializer);
|
||||
BuiltinSnapshotData builtin_snapshot(&builtin_serializer);
|
||||
SnapshotData partial_snapshot(&partial_serializer);
|
||||
@ -660,6 +691,7 @@ static void PartiallySerializeCustomContext(
|
||||
*partial_blob_out = WritePayload(partial_snapshot.RawData());
|
||||
*builtin_blob_out = WritePayload(builtin_snapshot.RawData());
|
||||
*startup_blob_out = WritePayload(startup_snapshot.RawData());
|
||||
*read_only_blob_out = WritePayload(read_only_snapshot.RawData());
|
||||
}
|
||||
v8_isolate->Dispose();
|
||||
}
|
||||
@ -669,10 +701,12 @@ UNINITIALIZED_TEST(PartialSerializerCustomContext) {
|
||||
DisableAlwaysOpt();
|
||||
Vector<const byte> startup_blob;
|
||||
Vector<const byte> builtin_blob;
|
||||
Vector<const byte> read_only_blob;
|
||||
Vector<const byte> partial_blob;
|
||||
PartiallySerializeCustomContext(&startup_blob, &builtin_blob, &partial_blob);
|
||||
PartiallySerializeCustomContext(&startup_blob, &builtin_blob, &read_only_blob,
|
||||
&partial_blob);
|
||||
|
||||
StartupBlobs blobs = {startup_blob, builtin_blob};
|
||||
StartupBlobs blobs = {startup_blob, builtin_blob, read_only_blob};
|
||||
v8::Isolate* v8_isolate = InitializeFromBlob(blobs);
|
||||
CHECK(v8_isolate);
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user