[snapshot] Continue splitting up Deserializer

Another pure refactoring CL. This extracts methods used only by Deserializer
subclasses.

Bug: v8:6624
Change-Id: Ib4dd7cdc591dff217e282e68a490c8c7129b9c96
Reviewed-on: https://chromium-review.googlesource.com/602188
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47211}
This commit is contained in:
Jakob Gruber 2017-08-08 08:48:34 +02:00 committed by Commit Bot
parent 650d65c951
commit 2e2069cdf6
9 changed files with 316 additions and 297 deletions

View File

@ -194,7 +194,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
return MaybeHandle<SharedFunctionInfo>();
}
ObjectDeserializer deserializer(&scd, false);
ObjectDeserializer deserializer(&scd);
deserializer.AddAttachedObject(source);
Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys();
for (int i = 0; i < code_stub_keys.length(); i++) {
@ -265,7 +265,7 @@ MaybeHandle<FixedArray> WasmCompiledModuleSerializer::DeserializeWasmModule(
return nothing;
}
ObjectDeserializer deserializer(&scd, true);
ObjectDeserializer deserializer(&scd);
deserializer.AddAttachedObject(isolate->native_context());
MaybeHandle<String> maybe_wire_bytes_as_string =

View File

@ -33,25 +33,9 @@ void Deserializer::DecodeReservation(
for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) current_chunk_[i] = 0;
}
void Deserializer::FlushICacheForNewIsolate() {
DCHECK(!deserializing_user_code_);
// The entire isolate is newly deserialized. Simply flush all code pages.
for (Page* p : *isolate_->heap()->code_space()) {
Assembler::FlushICache(isolate_, p->area_start(),
p->area_end() - p->area_start());
}
}
void Deserializer::FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects() {
DCHECK(deserializing_user_code_);
for (Code* code : new_code_objects_) {
// Record all references to embedded objects in the new code object.
isolate_->heap()->RecordWritesIntoCode(code);
if (FLAG_serialize_age_code) code->PreAge(isolate_);
Assembler::FlushICache(isolate_, code->instruction_start(),
code->instruction_size());
}
void Deserializer::RegisterDeserializedObjectsForBlackAllocation() {
isolate_->heap()->RegisterDeserializedObjectsForBlackAllocation(
reservations_, &deserialized_large_objects_, &allocated_maps_);
}
bool Deserializer::ReserveSpace() {
@ -83,126 +67,6 @@ void Deserializer::Initialize(Isolate* isolate) {
SerializedData::GetExtraReferences(external_reference_table_));
}
void Deserializer::Deserialize(Isolate* isolate) {
Initialize(isolate);
if (!ReserveSpace()) V8::FatalProcessOutOfMemory("deserializing context");
// No active threads.
DCHECK_NULL(isolate_->thread_manager()->FirstThreadStateInUse());
// No active handles.
DCHECK(isolate_->handle_scope_implementer()->blocks()->is_empty());
// Partial snapshot cache is not yet populated.
DCHECK(isolate_->partial_snapshot_cache()->is_empty());
// Builtins are not yet created.
DCHECK(!isolate_->builtins()->is_initialized());
{
DisallowHeapAllocation no_gc;
isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG_ROOT_LIST);
isolate_->heap()->IterateSmiRoots(this);
isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
isolate_->heap()->RepairFreeListsAfterDeserialization();
isolate_->heap()->IterateWeakRoots(this, VISIT_ALL);
DeserializeDeferredObjects();
FlushICacheForNewIsolate();
RestoreExternalReferenceRedirectors(&accessor_infos_);
}
isolate_->heap()->set_native_contexts_list(
isolate_->heap()->undefined_value());
// The allocation site list is build during root iteration, but if no sites
// were encountered then it needs to be initialized to undefined.
if (isolate_->heap()->allocation_sites_list() == Smi::kZero) {
isolate_->heap()->set_allocation_sites_list(
isolate_->heap()->undefined_value());
}
// Issue code events for newly deserialized code objects.
LOG_CODE_EVENT(isolate_, LogCodeObjects());
LOG_CODE_EVENT(isolate_, LogBytecodeHandlers());
LOG_CODE_EVENT(isolate_, LogCompiledFunctions());
isolate_->builtins()->MarkInitialized();
// If needed, print the dissassembly of deserialized code objects.
// Needs to be called after the builtins are marked as initialized, in order
// to display the builtin names.
PrintDisassembledCodeObjects();
if (FLAG_rehash_snapshot && can_rehash_) Rehash();
}
MaybeHandle<Object> Deserializer::DeserializePartial(
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
Initialize(isolate);
if (!ReserveSpace()) {
V8::FatalProcessOutOfMemory("deserialize context");
return MaybeHandle<Object>();
}
AddAttachedObject(global_proxy);
DisallowHeapAllocation no_gc;
// Keep track of the code space start and end pointers in case new
// code objects were unserialized
OldSpace* code_space = isolate_->heap()->code_space();
Address start_address = code_space->top();
Object* root;
VisitRootPointer(Root::kPartialSnapshotCache, &root);
DeserializeDeferredObjects();
DeserializeEmbedderFields(embedder_fields_deserializer);
isolate->heap()->RegisterDeserializedObjectsForBlackAllocation(
reservations_, &deserialized_large_objects_, &allocated_maps_);
// There's no code deserialized here. If this assert fires then that's
// changed and logging should be added to notify the profiler et al of the
// new code, which also has to be flushed from instruction cache.
CHECK_EQ(start_address, code_space->top());
if (FLAG_rehash_snapshot && can_rehash_) RehashContext(Context::cast(root));
return Handle<Object>(root, isolate);
}
MaybeHandle<HeapObject> Deserializer::DeserializeObject(Isolate* isolate) {
Initialize(isolate);
if (!ReserveSpace()) {
return MaybeHandle<HeapObject>();
} else {
deserializing_user_code_ = true;
HandleScope scope(isolate);
Handle<HeapObject> result;
{
DisallowHeapAllocation no_gc;
Object* root;
VisitRootPointer(Root::kPartialSnapshotCache, &root);
DeserializeDeferredObjects();
FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects();
result = Handle<HeapObject>(HeapObject::cast(root));
isolate->heap()->RegisterDeserializedObjectsForBlackAllocation(
reservations_, &deserialized_large_objects_, &allocated_maps_);
}
CommitPostProcessedObjects(isolate);
return scope.CloseAndEscape(result);
}
}
void Deserializer::Rehash() {
DCHECK(can_rehash_);
isolate_->heap()->InitializeHashSeed();
isolate_->heap()->string_table()->Rehash();
isolate_->heap()->weak_object_to_code_table()->Rehash();
SortMapDescriptors();
}
void Deserializer::RehashContext(Context* context) {
DCHECK(can_rehash_);
for (const auto& array : transition_arrays_) array->Sort();
context->global_object()->global_dictionary()->Rehash();
SortMapDescriptors();
}
void Deserializer::SortMapDescriptors() {
for (const auto& address : allocated_maps_) {
Map* map = Map::cast(HeapObject::FromAddress(address));
@ -266,81 +130,28 @@ void Deserializer::DeserializeDeferredObjects() {
}
}
void Deserializer::DeserializeEmbedderFields(
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
if (!source_.HasMore() || source_.Get() != kEmbedderFieldsData) return;
DisallowHeapAllocation no_gc;
DisallowJavascriptExecution no_js(isolate_);
DisallowCompilation no_compile(isolate_);
DCHECK_NOT_NULL(embedder_fields_deserializer.callback);
for (int code = source_.Get(); code != kSynchronize; code = source_.Get()) {
HandleScope scope(isolate_);
int space = code & kSpaceMask;
DCHECK(space <= kNumberOfSpaces);
DCHECK(code - space == kNewObject);
Handle<JSObject> obj(JSObject::cast(GetBackReferencedObject(space)),
isolate_);
int index = source_.GetInt();
int size = source_.GetInt();
byte* data = new byte[size];
source_.CopyRaw(data, size);
embedder_fields_deserializer.callback(v8::Utils::ToLocal(obj), index,
{reinterpret_cast<char*>(data), size},
embedder_fields_deserializer.data);
delete[] data;
}
StringTableInsertionKey::StringTableInsertionKey(String* string)
: StringTableKey(ComputeHashField(string)), string_(string) {
DCHECK(string->IsInternalizedString());
}
void Deserializer::PrintDisassembledCodeObjects() {
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_builtin_code) {
Heap* heap = isolate_->heap();
HeapIterator iterator(heap);
DisallowHeapAllocation no_gc;
CodeTracer::Scope tracing_scope(isolate_->GetCodeTracer());
OFStream os(tracing_scope.file());
for (HeapObject* obj = iterator.next(); obj != NULL;
obj = iterator.next()) {
if (obj->IsCode()) {
Code::cast(obj)->Disassemble(nullptr, os);
}
}
}
#endif
bool StringTableInsertionKey::IsMatch(Object* string) {
// We know that all entries in a hash table had their hash keys created.
// Use that knowledge to have fast failure.
if (Hash() != String::cast(string)->Hash()) return false;
// We want to compare the content of two internalized strings here.
return string_->SlowEquals(String::cast(string));
}
// Used to insert a deserialized internalized string into the string table.
class StringTableInsertionKey : public StringTableKey {
public:
explicit StringTableInsertionKey(String* string)
: StringTableKey(ComputeHashField(string)), string_(string) {
DCHECK(string->IsInternalizedString());
}
Handle<String> StringTableInsertionKey::AsHandle(Isolate* isolate) {
return handle(string_, isolate);
}
bool IsMatch(Object* string) override {
// We know that all entries in a hash table had their hash keys created.
// Use that knowledge to have fast failure.
if (Hash() != String::cast(string)->Hash()) return false;
// We want to compare the content of two internalized strings here.
return string_->SlowEquals(String::cast(string));
}
MUST_USE_RESULT Handle<String> AsHandle(Isolate* isolate) override {
return handle(string_, isolate);
}
private:
uint32_t ComputeHashField(String* string) {
// Make sure hash_field() is computed.
string->Hash();
return string->hash_field();
}
String* string_;
DisallowHeapAllocation no_gc;
};
uint32_t StringTableInsertionKey::ComputeHashField(String* string) {
// Make sure hash_field() is computed.
string->Hash();
return string->hash_field();
}
HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
if (deserializing_user_code()) {
@ -415,26 +226,6 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
return obj;
}
void Deserializer::CommitPostProcessedObjects(Isolate* isolate) {
StringTable::EnsureCapacityForDeserialization(
isolate, new_internalized_strings_.length());
for (Handle<String> string : new_internalized_strings_) {
StringTableInsertionKey key(*string);
DCHECK_NULL(StringTable::LookupKeyIfExists(isolate, &key));
StringTable::LookupKey(isolate, &key);
}
Heap* heap = isolate->heap();
Factory* factory = isolate->factory();
for (Handle<Script> script : new_scripts_) {
// Assign a new script id to avoid collision.
script->set_id(isolate_->heap()->NextScriptId());
// Add script to list.
Handle<Object> list = WeakFixedArray::Add(factory->script_list(), script);
heap->SetRootScriptList(*list);
}
}
HeapObject* Deserializer::GetBackReferencedObject(int space) {
HeapObject* obj;
SerializerReference back_reference =

View File

@ -39,9 +39,6 @@ class Deserializer : public SerializerDeserializer {
void SetRehashability(bool v) { can_rehash_ = v; }
protected:
// This section is temporary while the deserializer is being refactored into
// {object,partial,object}-deserializer.h.
// Create a deserializer from a snapshot byte source.
template <class Data>
Deserializer(Data* data, bool deserializing_user_code)
@ -58,30 +55,37 @@ class Deserializer : public SerializerDeserializer {
DecodeReservation(data->Reservations());
}
// Deserialize the snapshot into an empty heap.
void Deserialize(Isolate* isolate);
void Initialize(Isolate* isolate);
bool ReserveSpace();
void DeserializeDeferredObjects();
void RegisterDeserializedObjectsForBlackAllocation();
// Deserialize a single object and the objects reachable from it.
MaybeHandle<Object> DeserializePartial(
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer);
// This returns the address of an object that has been described in the
// snapshot by chunk index and offset.
HeapObject* GetBackReferencedObject(int space);
// Deserialize an object graph. Fail gracefully.
MaybeHandle<HeapObject> DeserializeObject(Isolate* isolate);
// Sort descriptors of deserialized maps using new string hashes.
void SortMapDescriptors();
Isolate* isolate() const { return isolate_; }
SnapshotByteSource* source() { return &source_; }
List<Code*>& new_code_objects() { return new_code_objects_; }
List<AccessorInfo*>* accessor_infos() { return &accessor_infos_; }
List<Handle<String>>& new_internalized_strings() {
return new_internalized_strings_;
}
List<Handle<Script>>& new_scripts() { return new_scripts_; }
List<TransitionArray*>& transition_arrays() { return transition_arrays_; }
bool deserializing_user_code() const { return deserializing_user_code_; }
bool can_rehash() const { return can_rehash_; }
private:
void VisitRootPointers(Root root, Object** start, Object** end) override;
void Synchronize(VisitorSynchronization::SyncTag tag) override;
void Initialize(Isolate* isolate);
bool deserializing_user_code() { return deserializing_user_code_; }
void DecodeReservation(Vector<const SerializedData::Reservation> res);
bool ReserveSpace();
void UnalignedCopy(Object** dest, Object** src) {
memcpy(dest, src, sizeof(*src));
}
@ -94,17 +98,6 @@ class Deserializer : public SerializerDeserializer {
next_alignment_ = static_cast<AllocationAlignment>(alignment);
}
void DeserializeDeferredObjects();
void DeserializeEmbedderFields(
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer);
void FlushICacheForNewIsolate();
void FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects();
void CommitPostProcessedObjects(Isolate* isolate);
void PrintDisassembledCodeObjects();
// Fills in some heap data in an area from start to end (non-inclusive). The
// space id is used for the write barrier. The object_address is the address
// of the object we are writing into, or NULL if we are not writing into an
@ -118,19 +111,6 @@ class Deserializer : public SerializerDeserializer {
// Special handling for serialized code like hooking up internalized strings.
HeapObject* PostProcessNewObject(HeapObject* obj, int space);
// This returns the address of an object that has been described in the
// snapshot by chunk index and offset.
HeapObject* GetBackReferencedObject(int space);
// Rehash after deserializing an isolate.
void Rehash();
// Rehash after deserializing a context.
void RehashContext(Context* context);
// Sort descriptors of deserialized maps using new string hashes.
void SortMapDescriptors();
// Cached current isolate.
Isolate* isolate_;
@ -156,11 +136,11 @@ class Deserializer : public SerializerDeserializer {
List<HeapObject*> deserialized_large_objects_;
List<Code*> new_code_objects_;
List<AccessorInfo*> accessor_infos_;
List<Handle<String> > new_internalized_strings_;
List<Handle<Script> > new_scripts_;
List<Handle<String>> new_internalized_strings_;
List<Handle<Script>> new_scripts_;
List<TransitionArray*> transition_arrays_;
bool deserializing_user_code_;
const bool deserializing_user_code_;
AllocationAlignment next_alignment_;
@ -170,6 +150,22 @@ class Deserializer : public SerializerDeserializer {
DISALLOW_COPY_AND_ASSIGN(Deserializer);
};
// Used to insert a deserialized internalized string into the string table.
class StringTableInsertionKey : public StringTableKey {
public:
explicit StringTableInsertionKey(String* string);
bool IsMatch(Object* string) override;
MUST_USE_RESULT Handle<String> AsHandle(Isolate* isolate) override;
private:
uint32_t ComputeHashField(String* string);
String* string_;
DisallowHeapAllocation no_gc;
};
} // namespace internal
} // namespace v8

View File

@ -4,6 +4,66 @@
#include "src/snapshot/object-deserializer.h"
#include "src/assembler-inl.h"
#include "src/isolate.h"
#include "src/objects.h"
#include "src/snapshot/code-serializer.h"
namespace v8 {
namespace internal {} // namespace internal
namespace internal {
MaybeHandle<HeapObject> ObjectDeserializer::Deserialize(Isolate* isolate) {
Initialize(isolate);
if (!ReserveSpace()) return MaybeHandle<HeapObject>();
DCHECK(deserializing_user_code());
HandleScope scope(isolate);
Handle<HeapObject> result;
{
DisallowHeapAllocation no_gc;
Object* root;
VisitRootPointer(Root::kPartialSnapshotCache, &root);
DeserializeDeferredObjects();
FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects();
result = Handle<HeapObject>(HeapObject::cast(root));
RegisterDeserializedObjectsForBlackAllocation();
}
CommitPostProcessedObjects();
return scope.CloseAndEscape(result);
}
void ObjectDeserializer::
FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects() {
DCHECK(deserializing_user_code());
for (Code* code : new_code_objects()) {
// Record all references to embedded objects in the new code object.
isolate()->heap()->RecordWritesIntoCode(code);
if (FLAG_serialize_age_code) code->PreAge(isolate());
Assembler::FlushICache(isolate(), code->instruction_start(),
code->instruction_size());
}
}
void ObjectDeserializer::CommitPostProcessedObjects() {
StringTable::EnsureCapacityForDeserialization(
isolate(), new_internalized_strings().length());
for (Handle<String> string : new_internalized_strings()) {
StringTableInsertionKey key(*string);
DCHECK_NULL(StringTable::LookupKeyIfExists(isolate(), &key));
StringTable::LookupKey(isolate(), &key);
}
Heap* heap = isolate()->heap();
Factory* factory = isolate()->factory();
for (Handle<Script> script : new_scripts()) {
// Assign a new script id to avoid collision.
script->set_id(isolate()->heap()->NextScriptId());
// Add script to list.
Handle<Object> list = WeakFixedArray::Add(factory->script_list(), script);
heap->SetRootScriptList(*list);
}
}
} // namespace internal
} // namespace v8

View File

@ -10,19 +10,22 @@
namespace v8 {
namespace internal {
class SerializedCodeData;
// Deserializes the object graph rooted at a given object.
// Currently, the ObjectDeserializer is only used to deserialize code objects
// and compiled wasm modules.
class ObjectDeserializer : public Deserializer {
class ObjectDeserializer final : public Deserializer {
public:
template <class Data>
ObjectDeserializer(Data* data, bool deserializing_user_code)
: Deserializer(data, deserializing_user_code) {}
explicit ObjectDeserializer(const SerializedCodeData* data)
: Deserializer(data, true) {}
// Deserialize an object graph. Fail gracefully.
MaybeHandle<HeapObject> Deserialize(Isolate* isolate) {
return DeserializeObject(isolate);
}
MaybeHandle<HeapObject> Deserialize(Isolate* isolate);
private:
void FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects();
void CommitPostProcessedObjects();
};
} // namespace internal

View File

@ -4,6 +4,75 @@
#include "src/snapshot/partial-deserializer.h"
#include "src/heap/heap-inl.h"
#include "src/snapshot/snapshot.h"
namespace v8 {
namespace internal {} // namespace internal
namespace internal {
MaybeHandle<Object> PartialDeserializer::Deserialize(
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
Initialize(isolate);
if (!ReserveSpace()) V8::FatalProcessOutOfMemory("PartialDeserializer");
AddAttachedObject(global_proxy);
DisallowHeapAllocation no_gc;
// Keep track of the code space start and end pointers in case new
// code objects were unserialized
OldSpace* code_space = isolate->heap()->code_space();
Address start_address = code_space->top();
Object* root;
VisitRootPointer(Root::kPartialSnapshotCache, &root);
DeserializeDeferredObjects();
DeserializeEmbedderFields(embedder_fields_deserializer);
RegisterDeserializedObjectsForBlackAllocation();
// There's no code deserialized here. If this assert fires then that's
// changed and logging should be added to notify the profiler et al of the
// new code, which also has to be flushed from instruction cache.
CHECK_EQ(start_address, code_space->top());
if (FLAG_rehash_snapshot && can_rehash()) RehashContext(Context::cast(root));
return Handle<Object>(root, isolate);
}
void PartialDeserializer::DeserializeEmbedderFields(
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
if (!source()->HasMore() || source()->Get() != kEmbedderFieldsData) return;
DisallowHeapAllocation no_gc;
DisallowJavascriptExecution no_js(isolate());
DisallowCompilation no_compile(isolate());
DCHECK_NOT_NULL(embedder_fields_deserializer.callback);
for (int code = source()->Get(); code != kSynchronize;
code = source()->Get()) {
HandleScope scope(isolate());
int space = code & kSpaceMask;
DCHECK(space <= kNumberOfSpaces);
DCHECK(code - space == kNewObject);
Handle<JSObject> obj(JSObject::cast(GetBackReferencedObject(space)),
isolate());
int index = source()->GetInt();
int size = source()->GetInt();
// TODO(yangguo,jgruber): Turn this into a reusable shared buffer.
byte* data = new byte[size];
source()->CopyRaw(data, size);
embedder_fields_deserializer.callback(v8::Utils::ToLocal(obj), index,
{reinterpret_cast<char*>(data), size},
embedder_fields_deserializer.data);
delete[] data;
}
}
void PartialDeserializer::RehashContext(Context* context) {
DCHECK(can_rehash());
for (const auto& array : transition_arrays()) array->Sort();
context->global_object()->global_dictionary()->Rehash();
SortMapDescriptors();
}
} // namespace internal
} // namespace v8

View File

@ -13,19 +13,23 @@ namespace internal {
// Deserializes the context-dependent object graph rooted at a given object.
// Currently, the only use-case is to deserialize native contexts.
// The PartialDeserializer is not expected to any deserialize code objects.
class PartialDeserializer : public Deserializer {
// The PartialDeserializer is not expected to deserialize any code objects.
class PartialDeserializer final : public Deserializer {
public:
explicit PartialDeserializer(SnapshotData* data)
explicit PartialDeserializer(const SnapshotData* data)
: Deserializer(data, false) {}
// Deserialize a single object and the objects reachable from it.
MaybeHandle<Object> Deserialize(
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
return DeserializePartial(isolate, global_proxy,
embedder_fields_deserializer);
}
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer);
private:
void DeserializeEmbedderFields(
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer);
// Rehash after deserializing a context.
void RehashContext(Context* context);
};
} // namespace internal

View File

@ -4,6 +4,97 @@
#include "src/snapshot/startup-deserializer.h"
#include "src/assembler-inl.h"
#include "src/heap/heap-inl.h"
#include "src/snapshot/snapshot.h"
namespace v8 {
namespace internal {} // namespace internal
namespace internal {
void StartupDeserializer::Deserialize(Isolate* isolate) {
Initialize(isolate);
if (!ReserveSpace()) V8::FatalProcessOutOfMemory("StartupDeserializer");
// No active threads.
DCHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
// No active handles.
DCHECK(isolate->handle_scope_implementer()->blocks()->is_empty());
// Partial snapshot cache is not yet populated.
DCHECK(isolate->partial_snapshot_cache()->is_empty());
// Builtins are not yet created.
DCHECK(!isolate->builtins()->is_initialized());
{
DisallowHeapAllocation no_gc;
isolate->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG_ROOT_LIST);
isolate->heap()->IterateSmiRoots(this);
isolate->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
isolate->heap()->RepairFreeListsAfterDeserialization();
isolate->heap()->IterateWeakRoots(this, VISIT_ALL);
DeserializeDeferredObjects();
FlushICacheForNewIsolate();
RestoreExternalReferenceRedirectors(accessor_infos());
}
isolate->heap()->set_native_contexts_list(isolate->heap()->undefined_value());
// The allocation site list is build during root iteration, but if no sites
// were encountered then it needs to be initialized to undefined.
if (isolate->heap()->allocation_sites_list() == Smi::kZero) {
isolate->heap()->set_allocation_sites_list(
isolate->heap()->undefined_value());
}
// Issue code events for newly deserialized code objects.
LOG_CODE_EVENT(isolate, LogCodeObjects());
LOG_CODE_EVENT(isolate, LogBytecodeHandlers());
LOG_CODE_EVENT(isolate, LogCompiledFunctions());
isolate->builtins()->MarkInitialized();
// If needed, print the dissassembly of deserialized code objects.
// Needs to be called after the builtins are marked as initialized, in order
// to display the builtin names.
PrintDisassembledCodeObjects();
if (FLAG_rehash_snapshot && can_rehash()) Rehash();
}
void StartupDeserializer::FlushICacheForNewIsolate() {
DCHECK(!deserializing_user_code());
// The entire isolate is newly deserialized. Simply flush all code pages.
for (Page* p : *isolate()->heap()->code_space()) {
Assembler::FlushICache(isolate(), p->area_start(),
p->area_end() - p->area_start());
}
}
void StartupDeserializer::PrintDisassembledCodeObjects() {
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_builtin_code) {
Heap* heap = isolate()->heap();
HeapIterator iterator(heap);
DisallowHeapAllocation no_gc;
CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
OFStream os(tracing_scope.file());
for (HeapObject* obj = iterator.next(); obj != NULL;
obj = iterator.next()) {
if (obj->IsCode()) {
Code::cast(obj)->Disassemble(nullptr, os);
}
}
}
#endif
}
void StartupDeserializer::Rehash() {
DCHECK(FLAG_rehash_snapshot && can_rehash());
isolate()->heap()->InitializeHashSeed();
isolate()->heap()->string_table()->Rehash();
isolate()->heap()->weak_object_to_code_table()->Rehash();
SortMapDescriptors();
}
} // namespace internal
} // namespace v8

View File

@ -12,15 +12,20 @@ namespace v8 {
namespace internal {
// Initializes an isolate with context-independent data from a given snapshot.
class StartupDeserializer : public Deserializer {
class StartupDeserializer final : public Deserializer {
public:
explicit StartupDeserializer(SnapshotData* data)
explicit StartupDeserializer(const SnapshotData* data)
: Deserializer(data, false) {}
// Deserialize the snapshot into an empty heap.
void Deserialize(Isolate* isolate) {
return Deserializer::Deserialize(isolate);
}
void Deserialize(Isolate* isolate);
private:
void FlushICacheForNewIsolate();
void PrintDisassembledCodeObjects();
// Rehash after deserializing an isolate.
void Rehash();
};
} // namespace internal