Commit f602712f authored by Dan Elphick's avatar Dan Elphick Committed by Commit Bot

[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: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56681}
parent fac6f63e
......@@ -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",
......
......@@ -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;
}
......
// 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
// 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_
// 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
// 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_
// 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
// 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);
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);
}
// 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);
// 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);
{
......
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