[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:
parent
650d65c951
commit
2e2069cdf6
@ -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 =
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user