Commit 2e2069cd authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[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: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47211}
parent 650d65c9
...@@ -194,7 +194,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( ...@@ -194,7 +194,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
return MaybeHandle<SharedFunctionInfo>(); return MaybeHandle<SharedFunctionInfo>();
} }
ObjectDeserializer deserializer(&scd, false); ObjectDeserializer deserializer(&scd);
deserializer.AddAttachedObject(source); deserializer.AddAttachedObject(source);
Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys(); Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys();
for (int i = 0; i < code_stub_keys.length(); i++) { for (int i = 0; i < code_stub_keys.length(); i++) {
...@@ -265,7 +265,7 @@ MaybeHandle<FixedArray> WasmCompiledModuleSerializer::DeserializeWasmModule( ...@@ -265,7 +265,7 @@ MaybeHandle<FixedArray> WasmCompiledModuleSerializer::DeserializeWasmModule(
return nothing; return nothing;
} }
ObjectDeserializer deserializer(&scd, true); ObjectDeserializer deserializer(&scd);
deserializer.AddAttachedObject(isolate->native_context()); deserializer.AddAttachedObject(isolate->native_context());
MaybeHandle<String> maybe_wire_bytes_as_string = MaybeHandle<String> maybe_wire_bytes_as_string =
......
...@@ -33,25 +33,9 @@ void Deserializer::DecodeReservation( ...@@ -33,25 +33,9 @@ void Deserializer::DecodeReservation(
for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) current_chunk_[i] = 0; for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) current_chunk_[i] = 0;
} }
void Deserializer::FlushICacheForNewIsolate() { void Deserializer::RegisterDeserializedObjectsForBlackAllocation() {
DCHECK(!deserializing_user_code_); isolate_->heap()->RegisterDeserializedObjectsForBlackAllocation(
// The entire isolate is newly deserialized. Simply flush all code pages. reservations_, &deserialized_large_objects_, &allocated_maps_);
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());
}
} }
bool Deserializer::ReserveSpace() { bool Deserializer::ReserveSpace() {
...@@ -83,126 +67,6 @@ void Deserializer::Initialize(Isolate* isolate) { ...@@ -83,126 +67,6 @@ void Deserializer::Initialize(Isolate* isolate) {
SerializedData::GetExtraReferences(external_reference_table_)); 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() { void Deserializer::SortMapDescriptors() {
for (const auto& address : allocated_maps_) { for (const auto& address : allocated_maps_) {
Map* map = Map::cast(HeapObject::FromAddress(address)); Map* map = Map::cast(HeapObject::FromAddress(address));
...@@ -266,81 +130,28 @@ void Deserializer::DeserializeDeferredObjects() { ...@@ -266,81 +130,28 @@ void Deserializer::DeserializeDeferredObjects() {
} }
} }
void Deserializer::DeserializeEmbedderFields( StringTableInsertionKey::StringTableInsertionKey(String* string)
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) { : StringTableKey(ComputeHashField(string)), string_(string) {
if (!source_.HasMore() || source_.Get() != kEmbedderFieldsData) return; DCHECK(string->IsInternalizedString());
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;
}
} }
void Deserializer::PrintDisassembledCodeObjects() { bool StringTableInsertionKey::IsMatch(Object* string) {
#ifdef ENABLE_DISASSEMBLER // We know that all entries in a hash table had their hash keys created.
if (FLAG_print_builtin_code) { // Use that knowledge to have fast failure.
Heap* heap = isolate_->heap(); if (Hash() != String::cast(string)->Hash()) return false;
HeapIterator iterator(heap); // We want to compare the content of two internalized strings here.
DisallowHeapAllocation no_gc; return string_->SlowEquals(String::cast(string));
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
} }
// Used to insert a deserialized internalized string into the string table. Handle<String> StringTableInsertionKey::AsHandle(Isolate* isolate) {
class StringTableInsertionKey : public StringTableKey { return handle(string_, isolate);
public: }
explicit StringTableInsertionKey(String* string)
: StringTableKey(ComputeHashField(string)), string_(string) {
DCHECK(string->IsInternalizedString());
}
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_; uint32_t StringTableInsertionKey::ComputeHashField(String* string) {
DisallowHeapAllocation no_gc; // Make sure hash_field() is computed.
}; string->Hash();
return string->hash_field();
}
HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) { HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
if (deserializing_user_code()) { if (deserializing_user_code()) {
...@@ -415,26 +226,6 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) { ...@@ -415,26 +226,6 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
return obj; 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* Deserializer::GetBackReferencedObject(int space) {
HeapObject* obj; HeapObject* obj;
SerializerReference back_reference = SerializerReference back_reference =
......
...@@ -39,9 +39,6 @@ class Deserializer : public SerializerDeserializer { ...@@ -39,9 +39,6 @@ class Deserializer : public SerializerDeserializer {
void SetRehashability(bool v) { can_rehash_ = v; } void SetRehashability(bool v) { can_rehash_ = v; }
protected: 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. // Create a deserializer from a snapshot byte source.
template <class Data> template <class Data>
Deserializer(Data* data, bool deserializing_user_code) Deserializer(Data* data, bool deserializing_user_code)
...@@ -58,30 +55,37 @@ class Deserializer : public SerializerDeserializer { ...@@ -58,30 +55,37 @@ class Deserializer : public SerializerDeserializer {
DecodeReservation(data->Reservations()); DecodeReservation(data->Reservations());
} }
// Deserialize the snapshot into an empty heap. void Initialize(Isolate* isolate);
void Deserialize(Isolate* isolate); bool ReserveSpace();
void DeserializeDeferredObjects();
void RegisterDeserializedObjectsForBlackAllocation();
// Deserialize a single object and the objects reachable from it. // This returns the address of an object that has been described in the
MaybeHandle<Object> DeserializePartial( // snapshot by chunk index and offset.
Isolate* isolate, Handle<JSGlobalProxy> global_proxy, HeapObject* GetBackReferencedObject(int space);
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer);
// Deserialize an object graph. Fail gracefully. // Sort descriptors of deserialized maps using new string hashes.
MaybeHandle<HeapObject> DeserializeObject(Isolate* isolate); 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: private:
void VisitRootPointers(Root root, Object** start, Object** end) override; void VisitRootPointers(Root root, Object** start, Object** end) override;
void Synchronize(VisitorSynchronization::SyncTag tag) 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); void DecodeReservation(Vector<const SerializedData::Reservation> res);
bool ReserveSpace();
void UnalignedCopy(Object** dest, Object** src) { void UnalignedCopy(Object** dest, Object** src) {
memcpy(dest, src, sizeof(*src)); memcpy(dest, src, sizeof(*src));
} }
...@@ -94,17 +98,6 @@ class Deserializer : public SerializerDeserializer { ...@@ -94,17 +98,6 @@ class Deserializer : public SerializerDeserializer {
next_alignment_ = static_cast<AllocationAlignment>(alignment); 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 // 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 // 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 // of the object we are writing into, or NULL if we are not writing into an
...@@ -118,19 +111,6 @@ class Deserializer : public SerializerDeserializer { ...@@ -118,19 +111,6 @@ class Deserializer : public SerializerDeserializer {
// Special handling for serialized code like hooking up internalized strings. // Special handling for serialized code like hooking up internalized strings.
HeapObject* PostProcessNewObject(HeapObject* obj, int space); 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. // Cached current isolate.
Isolate* isolate_; Isolate* isolate_;
...@@ -156,11 +136,11 @@ class Deserializer : public SerializerDeserializer { ...@@ -156,11 +136,11 @@ class Deserializer : public SerializerDeserializer {
List<HeapObject*> deserialized_large_objects_; List<HeapObject*> deserialized_large_objects_;
List<Code*> new_code_objects_; List<Code*> new_code_objects_;
List<AccessorInfo*> accessor_infos_; List<AccessorInfo*> accessor_infos_;
List<Handle<String> > new_internalized_strings_; List<Handle<String>> new_internalized_strings_;
List<Handle<Script> > new_scripts_; List<Handle<Script>> new_scripts_;
List<TransitionArray*> transition_arrays_; List<TransitionArray*> transition_arrays_;
bool deserializing_user_code_; const bool deserializing_user_code_;
AllocationAlignment next_alignment_; AllocationAlignment next_alignment_;
...@@ -170,6 +150,22 @@ class Deserializer : public SerializerDeserializer { ...@@ -170,6 +150,22 @@ class Deserializer : public SerializerDeserializer {
DISALLOW_COPY_AND_ASSIGN(Deserializer); 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 internal
} // namespace v8 } // namespace v8
......
...@@ -4,6 +4,66 @@ ...@@ -4,6 +4,66 @@
#include "src/snapshot/object-deserializer.h" #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 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 } // namespace v8
...@@ -10,19 +10,22 @@ ...@@ -10,19 +10,22 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class SerializedCodeData;
// Deserializes the object graph rooted at a given object. // Deserializes the object graph rooted at a given object.
// Currently, the ObjectDeserializer is only used to deserialize code objects // Currently, the ObjectDeserializer is only used to deserialize code objects
// and compiled wasm modules. // and compiled wasm modules.
class ObjectDeserializer : public Deserializer { class ObjectDeserializer final : public Deserializer {
public: public:
template <class Data> explicit ObjectDeserializer(const SerializedCodeData* data)
ObjectDeserializer(Data* data, bool deserializing_user_code) : Deserializer(data, true) {}
: Deserializer(data, deserializing_user_code) {}
// Deserialize an object graph. Fail gracefully. // Deserialize an object graph. Fail gracefully.
MaybeHandle<HeapObject> Deserialize(Isolate* isolate) { MaybeHandle<HeapObject> Deserialize(Isolate* isolate);
return DeserializeObject(isolate);
} private:
void FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects();
void CommitPostProcessedObjects();
}; };
} // namespace internal } // namespace internal
......
...@@ -4,6 +4,75 @@ ...@@ -4,6 +4,75 @@
#include "src/snapshot/partial-deserializer.h" #include "src/snapshot/partial-deserializer.h"
#include "src/heap/heap-inl.h"
#include "src/snapshot/snapshot.h"
namespace v8 { 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 } // namespace v8
...@@ -13,19 +13,23 @@ namespace internal { ...@@ -13,19 +13,23 @@ namespace internal {
// Deserializes the context-dependent object graph rooted at a given object. // Deserializes the context-dependent object graph rooted at a given object.
// Currently, the only use-case is to deserialize native contexts. // Currently, the only use-case is to deserialize native contexts.
// The PartialDeserializer is not expected to any deserialize code objects. // The PartialDeserializer is not expected to deserialize any code objects.
class PartialDeserializer : public Deserializer { class PartialDeserializer final : public Deserializer {
public: public:
explicit PartialDeserializer(SnapshotData* data) explicit PartialDeserializer(const SnapshotData* data)
: Deserializer(data, false) {} : Deserializer(data, false) {}
// Deserialize a single object and the objects reachable from it. // Deserialize a single object and the objects reachable from it.
MaybeHandle<Object> Deserialize( MaybeHandle<Object> Deserialize(
Isolate* isolate, Handle<JSGlobalProxy> global_proxy, Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) { v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer);
return DeserializePartial(isolate, global_proxy,
embedder_fields_deserializer); private:
} void DeserializeEmbedderFields(
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer);
// Rehash after deserializing a context.
void RehashContext(Context* context);
}; };
} // namespace internal } // namespace internal
......
...@@ -4,6 +4,97 @@ ...@@ -4,6 +4,97 @@
#include "src/snapshot/startup-deserializer.h" #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 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 } // namespace v8
...@@ -12,15 +12,20 @@ namespace v8 { ...@@ -12,15 +12,20 @@ namespace v8 {
namespace internal { namespace internal {
// Initializes an isolate with context-independent data from a given snapshot. // Initializes an isolate with context-independent data from a given snapshot.
class StartupDeserializer : public Deserializer { class StartupDeserializer final : public Deserializer {
public: public:
explicit StartupDeserializer(SnapshotData* data) explicit StartupDeserializer(const SnapshotData* data)
: Deserializer(data, false) {} : Deserializer(data, false) {}
// Deserialize the snapshot into an empty heap. // Deserialize the snapshot into an empty heap.
void Deserialize(Isolate* isolate) { void Deserialize(Isolate* isolate);
return Deserializer::Deserialize(isolate);
} private:
void FlushICacheForNewIsolate();
void PrintDisassembledCodeObjects();
// Rehash after deserializing an isolate.
void Rehash();
}; };
} // namespace internal } // namespace internal
......
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