blob: 06c5094782c7cb6f2df16698ffc0be7357bae2cb [file] [log] [blame]
// 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/api.h"
#include "src/diagnostics/code-tracer.h"
#include "src/execution/v8threads.h"
#include "src/handles/global-handles.h"
#include "src/heap/read-only-heap.h"
#include "src/objects/objects-inl.h"
#include "src/objects/slots.h"
#include "src/snapshot/startup-serializer.h"
namespace v8 {
namespace internal {
ReadOnlySerializer::ReadOnlySerializer(Isolate* isolate,
Snapshot::SerializerFlags flags)
: RootsSerializer(isolate, flags, RootIndex::kFirstReadOnlyRoot)
#ifdef DEBUG
,
serialized_objects_(isolate->heap()),
did_serialize_not_mapped_symbol_(false)
#endif
{
STATIC_ASSERT(RootIndex::kFirstReadOnlyRoot == RootIndex::kFirstRoot);
}
ReadOnlySerializer::~ReadOnlySerializer() {
OutputStatistics("ReadOnlySerializer");
}
void ReadOnlySerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
CHECK(ReadOnlyHeap::Contains(*obj));
CHECK_IMPLIES(obj->IsString(), obj->IsInternalizedString());
// There should be no references to the not_mapped_symbol except for the entry
// in the root table, so don't try to serialize a reference and rely on the
// below CHECK(!did_serialize_not_mapped_symbol_) to make sure it doesn't
// serialize twice.
if (*obj != ReadOnlyRoots(isolate()).not_mapped_symbol()) {
if (SerializeHotObject(obj)) return;
if (IsRootAndHasBeenSerialized(*obj) && SerializeRoot(obj)) {
return;
}
if (SerializeBackReference(obj)) return;
}
CheckRehashability(*obj);
// Object has not yet been serialized. Serialize it here.
ObjectSerializer object_serializer(this, obj, &sink_);
object_serializer.Serialize();
#ifdef DEBUG
if (*obj == ReadOnlyRoots(isolate()).not_mapped_symbol()) {
CHECK(!did_serialize_not_mapped_symbol_);
did_serialize_not_mapped_symbol_ = true;
} else {
CHECK_NULL(serialized_objects_.Find(obj));
// There's no "IdentitySet", so use an IdentityMap with a value that is
// later ignored.
serialized_objects_.Insert(obj, 0);
}
#endif
}
void ReadOnlySerializer::SerializeReadOnlyRoots() {
// No active threads.
CHECK_NULL(isolate()->thread_manager()->FirstThreadStateInUse());
// No active or weak handles.
CHECK_IMPLIES(!allow_active_isolate_for_testing(),
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,
FullObjectSlot(&undefined));
SerializeDeferredObjects();
Pad();
#ifdef DEBUG
// Check that every object on read-only heap is reachable (and was
// serialized).
ReadOnlyHeapObjectIterator iterator(isolate()->read_only_heap());
for (HeapObject object = iterator.Next(); !object.is_null();
object = iterator.Next()) {
if (object == ReadOnlyRoots(isolate()).not_mapped_symbol()) {
CHECK(did_serialize_not_mapped_symbol_);
} else {
CHECK_NOT_NULL(serialized_objects_.Find(object));
}
}
#endif
}
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;
}
// Defer objects with special alignment requirements until the filler roots
// are serialized.
return HeapObject::RequiredAlignment(object.map()) != kWordAligned;
}
bool ReadOnlySerializer::SerializeUsingReadOnlyObjectCache(
SnapshotByteSink* sink, Handle<HeapObject> obj) {
if (!ReadOnlyHeap::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.
sink->Put(kReadOnlyObjectCache, "ReadOnlyObjectCache");
sink->PutInt(cache_index, "read_only_object_cache_index");
return true;
}
} // namespace internal
} // namespace v8