[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>();
|
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(
|
|||||||
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(
|
|||||||
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) {
|
|||||||
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() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
uint32_t StringTableInsertionKey::ComputeHashField(String* string) {
|
||||||
// We know that all entries in a hash table had their hash keys created.
|
// Make sure hash_field() is computed.
|
||||||
// Use that knowledge to have fast failure.
|
string->Hash();
|
||||||
if (Hash() != String::cast(string)->Hash()) return false;
|
return string->hash_field();
|
||||||
// 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
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) {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
// 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 {
|
|||||||
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 {
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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 @@
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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 {
|
|||||||
|
|
||||||
// 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 @@
|
|||||||
|
|
||||||
#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 {
|
|||||||
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
|
||||||
|
Loading…
Reference in New Issue
Block a user