[serializer] Cache instance type in PostProcessNewObject

Rather than having repeated IsFoo checks in PostProcessNewObject, which
means repeated handle accesses, map word accesses, and map pointer
decompressions, cache the instance type once and check it with
InstanceTypeChecker.

This gives a measurable 2-3% improvement in deserialization time (in my
informal local measurements).

Bug: chromium:1075999
Change-Id: I3e11588ad5d1c6ee2bbf93b82fa52c66496a325c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2440578
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70301}
This commit is contained in:
Leszek Swirski 2020-10-01 18:24:19 +02:00 committed by Commit Bot
parent 4e7c99abda
commit c8f73f2266
4 changed files with 51 additions and 41 deletions

View File

@ -6,10 +6,10 @@
#define V8_OBJECTS_HEAP_OBJECT_H_
#include "src/common/globals.h"
#include "src/roots/roots.h"
#include "src/objects/instance-type.h"
#include "src/objects/objects.h"
#include "src/objects/tagged-field.h"
#include "src/roots/roots.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@ -181,6 +181,7 @@ class HeapObject : public Object {
// Whether the object needs rehashing. That is the case if the object's
// content depends on FLAG_hash_seed. When the object is deserialized into
// a heap with a different hash seed, these objects need to adapt.
bool NeedsRehashing(InstanceType instance_type) const;
bool NeedsRehashing() const;
// Rehashing support is not implemented for all objects that need rehashing.

View File

@ -2306,7 +2306,12 @@ int HeapObject::SizeFromMap(Map map) const {
}
bool HeapObject::NeedsRehashing() const {
switch (map().instance_type()) {
return NeedsRehashing(map().instance_type());
}
bool HeapObject::NeedsRehashing(InstanceType instance_type) const {
DCHECK_EQ(instance_type, map().instance_type());
switch (instance_type) {
case DESCRIPTOR_ARRAY_TYPE:
case STRONG_DESCRIPTOR_ARRAY_TYPE:
return DescriptorArray::cast(*this).number_of_descriptors() > 1;

View File

@ -303,12 +303,14 @@ uint32_t StringTableInsertionKey::ComputeHashField(String string) {
return string.hash_field();
}
void Deserializer::PostProcessNewObject(Handle<HeapObject> obj,
void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
SnapshotSpace space) {
DCHECK_EQ(*map, obj->map());
DisallowGarbageCollection no_gc;
InstanceType instance_type = map->instance_type();
if ((FLAG_rehash_snapshot && can_rehash_) || deserializing_user_code()) {
if (obj->IsString()) {
if (InstanceTypeChecker::IsString(instance_type)) {
// Uninitialize hash field as we need to recompute the hash.
Handle<String> string = Handle<String>::cast(obj);
string->set_hash_field(String::kEmptyHashField);
@ -317,33 +319,31 @@ void Deserializer::PostProcessNewObject(Handle<HeapObject> obj,
if (space == SnapshotSpace::kReadOnlyHeap) {
to_rehash_.push_back(obj);
}
} else if (obj->NeedsRehashing()) {
} else if (obj->NeedsRehashing(instance_type)) {
to_rehash_.push_back(obj);
}
}
if (deserializing_user_code()) {
if (obj->IsString()) {
if (InstanceTypeChecker::IsInternalizedString(instance_type)) {
// Canonicalize the internalized string. If it already exists in the
// string table, set it to forward to the existing one.
Handle<String> string = Handle<String>::cast(obj);
if (string->IsInternalizedString()) {
// Canonicalize the internalized string. If it already exists in the
// string table, set it to forward to the existing one.
StringTableInsertionKey key(string);
Handle<String> result =
isolate()->string_table()->LookupKey(isolate(), &key);
StringTableInsertionKey key(string);
Handle<String> result =
isolate()->string_table()->LookupKey(isolate(), &key);
if (FLAG_thin_strings && *result != *string) {
string->MakeThin(isolate(), *result);
// Mutate the given object handle so that the backreference entry is
// also updated.
obj.PatchValue(*result);
}
return;
if (FLAG_thin_strings && *result != *string) {
string->MakeThin(isolate(), *result);
// Mutate the given object handle so that the backreference entry is
// also updated.
obj.PatchValue(*result);
}
} else if (obj->IsScript()) {
return;
} else if (InstanceTypeChecker::IsScript(instance_type)) {
new_scripts_.push_back(Handle<Script>::cast(obj));
} else if (obj->IsAllocationSite()) {
} else if (InstanceTypeChecker::IsAllocationSite(instance_type)) {
// We should link new allocation sites, but we can't do this immediately
// because |AllocationSite::HasWeakNext()| internally accesses
// |Heap::roots_| that may not have been initialized yet. So defer this to
@ -353,28 +353,31 @@ void Deserializer::PostProcessNewObject(Handle<HeapObject> obj,
DCHECK(CanBeDeferred(*obj));
}
}
if (obj->IsScript()) {
if (InstanceTypeChecker::IsScript(instance_type)) {
LogScriptEvents(Script::cast(*obj));
} else if (obj->IsCode()) {
} else if (InstanceTypeChecker::IsCode(instance_type)) {
// We flush all code pages after deserializing the startup snapshot.
// Hence we only remember each individual code object when deserializing
// user code.
if (deserializing_user_code()) {
new_code_objects_.push_back(Handle<Code>::cast(obj));
}
} else if (FLAG_trace_maps && obj->IsMap()) {
// Keep track of all seen Maps to log them later since they might be only
// partially initialized at this point.
new_maps_.push_back(Handle<Map>::cast(obj));
} else if (obj->IsAccessorInfo()) {
} else if (InstanceTypeChecker::IsMap(instance_type)) {
if (FLAG_trace_maps) {
// Keep track of all seen Maps to log them later since they might be only
// partially initialized at this point.
new_maps_.push_back(Handle<Map>::cast(obj));
}
} else if (InstanceTypeChecker::IsAccessorInfo(instance_type)) {
#ifdef USE_SIMULATOR
accessor_infos_.push_back(Handle<AccessorInfo>::cast(obj));
#endif
} else if (obj->IsCallHandlerInfo()) {
} else if (InstanceTypeChecker::IsCallHandlerInfo(instance_type)) {
#ifdef USE_SIMULATOR
call_handler_infos_.push_back(Handle<CallHandlerInfo>::cast(obj));
#endif
} else if (obj->IsExternalString()) {
} else if (InstanceTypeChecker::IsExternalString(instance_type)) {
Handle<ExternalString> string = Handle<ExternalString>::cast(obj);
uint32_t index = string->GetResourceRefForDeserialization();
Address address =
@ -384,7 +387,7 @@ void Deserializer::PostProcessNewObject(Handle<HeapObject> obj,
isolate()->heap()->UpdateExternalString(*string, 0,
string->ExternalPayloadSize());
isolate()->heap()->RegisterExternalString(*string);
} else if (obj->IsJSDataView()) {
} else if (InstanceTypeChecker::IsJSDataView(instance_type)) {
Handle<JSDataView> data_view = Handle<JSDataView>::cast(obj);
JSArrayBuffer buffer = JSArrayBuffer::cast(data_view->buffer());
void* backing_store = nullptr;
@ -399,7 +402,7 @@ void Deserializer::PostProcessNewObject(Handle<HeapObject> obj,
data_view->set_data_pointer(
isolate(),
reinterpret_cast<uint8_t*>(backing_store) + data_view->byte_offset());
} else if (obj->IsJSTypedArray()) {
} else if (InstanceTypeChecker::IsJSTypedArray(instance_type)) {
Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(obj);
// Fixup typed array pointers.
if (typed_array->is_on_heap()) {
@ -420,7 +423,7 @@ void Deserializer::PostProcessNewObject(Handle<HeapObject> obj,
typed_array->SetOffHeapDataPtr(isolate(), start,
typed_array->byte_offset());
}
} else if (obj->IsJSArrayBuffer()) {
} else if (InstanceTypeChecker::IsJSArrayBuffer(instance_type)) {
Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(obj);
// Postpone allocation of backing store to avoid triggering the GC.
if (buffer->GetBackingStoreRefForDeserialization() != kNullRefSentinel) {
@ -429,20 +432,20 @@ void Deserializer::PostProcessNewObject(Handle<HeapObject> obj,
buffer->AllocateExternalPointerEntries(isolate());
buffer->set_backing_store(isolate(), nullptr);
}
} else if (obj->IsBytecodeArray()) {
} else if (InstanceTypeChecker::IsBytecodeArray(instance_type)) {
// TODO(mythria): Remove these once we store the default values for these
// fields in the serializer.
Handle<BytecodeArray> bytecode_array = Handle<BytecodeArray>::cast(obj);
bytecode_array->set_osr_loop_nesting_level(0);
} else if (obj->IsDescriptorArray()) {
DCHECK(obj->IsStrongDescriptorArray());
} else if (InstanceTypeChecker::IsDescriptorArray(instance_type)) {
DCHECK(InstanceTypeChecker::IsStrongDescriptorArray(instance_type));
Handle<DescriptorArray> descriptors = Handle<DescriptorArray>::cast(obj);
new_descriptor_arrays_.push_back(descriptors);
}
// Check alignment.
DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(),
HeapObject::RequiredAlignment(obj->map())));
HeapObject::RequiredAlignment(*map)));
}
HeapObjectReferenceType Deserializer::GetAndResetNextReferenceType() {
@ -519,7 +522,7 @@ Handle<HeapObject> Deserializer::ReadObject(SnapshotSpace space) {
back_refs_.push_back(obj);
ReadData(obj, 1, size_in_tagged);
PostProcessNewObject(obj, space);
PostProcessNewObject(map, obj, space);
DCHECK(!obj->IsThinString(isolate()));
@ -552,7 +555,7 @@ Handle<HeapObject> Deserializer::ReadMetaMap() {
Map::unchecked_cast(*obj).set_instance_type(MAP_TYPE);
ReadData(obj, 1, size_in_tagged);
PostProcessNewObject(obj, space);
PostProcessNewObject(Handle<Map>::cast(obj), obj, space);
return obj;
}

View File

@ -174,7 +174,8 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
int ReadRepeatedObject(SlotGetter slot_getter, int repeat_count);
// Special handling for serialized code like hooking up internalized strings.
void PostProcessNewObject(Handle<HeapObject> obj, SnapshotSpace space);
void PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
SnapshotSpace space);
HeapObject Allocate(SnapshotSpace space, int size,
AllocationAlignment alignment);