[snapshot][ptr-compr] Simplify deserialization of references embedded in code
... and use RelocInfo iteration instead of skip-and-unaligned-write sequences. This is a step towards avoiding unaligned stores via UnalignedSlot. Various cleanup CLs will follow. Bug: v8:8794 Change-Id: I62faedfa1c1ababe4b185fa8d7f2c6c1baa5cf79 Reviewed-on: https://chromium-review.googlesource.com/c/1456579 Commit-Queue: Igor Sheludko <ishell@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#59443}
This commit is contained in:
parent
7a8cd55146
commit
7e914db539
@ -589,22 +589,22 @@ class Code::BodyDescriptor final : public BodyDescriptorBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr int kRelocModeMask =
|
||||||
|
RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
|
||||||
|
RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
|
||||||
|
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
|
||||||
|
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
|
||||||
|
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
|
||||||
|
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
|
||||||
|
RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) |
|
||||||
|
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
|
||||||
|
|
||||||
template <typename ObjectVisitor>
|
template <typename ObjectVisitor>
|
||||||
static inline void IterateBody(Map map, HeapObject obj, ObjectVisitor* v) {
|
static inline void IterateBody(Map map, HeapObject obj, ObjectVisitor* v) {
|
||||||
static constexpr int kModeMask =
|
|
||||||
RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
|
|
||||||
RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
|
|
||||||
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
|
|
||||||
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
|
|
||||||
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
|
|
||||||
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
|
|
||||||
RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) |
|
|
||||||
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
|
|
||||||
|
|
||||||
// GC does not visit data/code in the header and in the body directly.
|
// GC does not visit data/code in the header and in the body directly.
|
||||||
IteratePointers(obj, kRelocationInfoOffset, kDataStart, v);
|
IteratePointers(obj, kRelocationInfoOffset, kDataStart, v);
|
||||||
|
|
||||||
RelocIterator it(Code::cast(obj), kModeMask);
|
RelocIterator it(Code::cast(obj), kRelocModeMask);
|
||||||
v->VisitRelocInfo(&it);
|
v->VisitRelocInfo(&it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "src/interpreter/interpreter.h"
|
#include "src/interpreter/interpreter.h"
|
||||||
#include "src/isolate.h"
|
#include "src/isolate.h"
|
||||||
#include "src/log.h"
|
#include "src/log.h"
|
||||||
|
#include "src/objects-body-descriptors-inl.h"
|
||||||
#include "src/objects/api-callbacks.h"
|
#include "src/objects/api-callbacks.h"
|
||||||
#include "src/objects/cell-inl.h"
|
#include "src/objects/cell-inl.h"
|
||||||
#include "src/objects/hash-table.h"
|
#include "src/objects/hash-table.h"
|
||||||
@ -367,6 +368,16 @@ HeapObject Deserializer::GetBackReferencedObject(int space) {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HeapObject Deserializer::ReadObject() {
|
||||||
|
MaybeObject object;
|
||||||
|
// We are reading to a location outside of JS heap, so pass NEW_SPACE to
|
||||||
|
// avoid triggering write barriers.
|
||||||
|
bool filled = ReadData(UnalignedSlot(&object), UnalignedSlot(&object + 1),
|
||||||
|
NEW_SPACE, kNullAddress);
|
||||||
|
CHECK(filled);
|
||||||
|
return object.GetHeapObjectAssumeStrong();
|
||||||
|
}
|
||||||
|
|
||||||
HeapObject Deserializer::ReadObject(int space_number) {
|
HeapObject Deserializer::ReadObject(int space_number) {
|
||||||
const int size = source_.GetInt() << kObjectAlignmentBits;
|
const int size = source_.GetInt() << kObjectAlignmentBits;
|
||||||
|
|
||||||
@ -393,21 +404,114 @@ HeapObject Deserializer::ReadObject(int space_number) {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Deserializer::ReadCodeObjectBody(int space_number,
|
||||||
|
Address code_object_address) {
|
||||||
|
// At this point the code object is already allocated, its map field is
|
||||||
|
// initialized and its raw data fields and code stream are also read.
|
||||||
|
// Now we read the rest of code header's fields.
|
||||||
|
UnalignedSlot current(code_object_address + HeapObject::kHeaderSize);
|
||||||
|
UnalignedSlot limit(code_object_address + Code::kDataStart);
|
||||||
|
bool filled = ReadData(current, limit, space_number, code_object_address);
|
||||||
|
CHECK(filled);
|
||||||
|
|
||||||
|
// Now iterate RelocInfos the same way it was done by the serialzier and
|
||||||
|
// deserialize respective data into RelocInfos.
|
||||||
|
Code code = Code::cast(HeapObject::FromAddress(code_object_address));
|
||||||
|
RelocIterator it(code, Code::BodyDescriptor::kRelocModeMask);
|
||||||
|
for (; !it.done(); it.next()) {
|
||||||
|
RelocInfo rinfo = *it.rinfo();
|
||||||
|
rinfo.Visit(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::VisitCodeTarget(Code host, RelocInfo* rinfo) {
|
||||||
|
HeapObject object = ReadObject();
|
||||||
|
rinfo->set_target_address(Code::cast(object)->raw_instruction_start());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::VisitEmbeddedPointer(Code host, RelocInfo* rinfo) {
|
||||||
|
HeapObject object = ReadObject();
|
||||||
|
// Embedded object reference must be a strong one.
|
||||||
|
rinfo->set_target_object(isolate_->heap(), object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::VisitRuntimeEntry(Code host, RelocInfo* rinfo) {
|
||||||
|
// We no longer serialize code that contains runtime entries.
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::VisitExternalReference(Code host, RelocInfo* rinfo) {
|
||||||
|
byte data = source_.Get();
|
||||||
|
CHECK(data == kExternalReference + kPlain + kStartOfObject ||
|
||||||
|
data == kExternalReference + kFromCode + kStartOfObject);
|
||||||
|
|
||||||
|
uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
|
||||||
|
Address address = external_reference_table_->address(reference_id);
|
||||||
|
|
||||||
|
DCHECK_EQ(rinfo->IsCodedSpecially(),
|
||||||
|
data == kExternalReference + kFromCode + kStartOfObject);
|
||||||
|
if (data == kExternalReference + kFromCode + kStartOfObject) {
|
||||||
|
Address location_of_branch_data = rinfo->pc();
|
||||||
|
Assembler::deserialization_set_special_target_at(location_of_branch_data,
|
||||||
|
host, address);
|
||||||
|
} else {
|
||||||
|
WriteUnalignedValue(rinfo->target_address_address(), address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::VisitInternalReference(Code host, RelocInfo* rinfo) {
|
||||||
|
byte data = source_.Get();
|
||||||
|
CHECK(data == kInternalReference || data == kInternalReferenceEncoded);
|
||||||
|
|
||||||
|
// Internal reference address is not encoded via skip, but by offset
|
||||||
|
// from code entry.
|
||||||
|
int pc_offset = source_.GetInt();
|
||||||
|
int target_offset = source_.GetInt();
|
||||||
|
DCHECK(0 <= pc_offset && pc_offset <= host->raw_instruction_size());
|
||||||
|
DCHECK(0 <= target_offset && target_offset <= host->raw_instruction_size());
|
||||||
|
Address pc = host->entry() + pc_offset;
|
||||||
|
// TODO(ishell): don't encode pc_offset as it can be taken from the rinfo.
|
||||||
|
DCHECK_EQ(pc, rinfo->pc());
|
||||||
|
Address target = host->entry() + target_offset;
|
||||||
|
Assembler::deserialization_set_target_internal_reference_at(
|
||||||
|
pc, target,
|
||||||
|
data == kInternalReference ? RelocInfo::INTERNAL_REFERENCE
|
||||||
|
: RelocInfo::INTERNAL_REFERENCE_ENCODED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::VisitOffHeapTarget(Code host, RelocInfo* rinfo) {
|
||||||
|
DCHECK(FLAG_embedded_builtins);
|
||||||
|
byte data = source_.Get();
|
||||||
|
CHECK_EQ(data, kOffHeapTarget);
|
||||||
|
|
||||||
|
int builtin_index = source_.GetInt();
|
||||||
|
DCHECK(Builtins::IsBuiltinId(builtin_index));
|
||||||
|
|
||||||
|
CHECK_NOT_NULL(isolate_->embedded_blob());
|
||||||
|
EmbeddedData d = EmbeddedData::FromBlob();
|
||||||
|
Address address = d.InstructionStartOfBuiltin(builtin_index);
|
||||||
|
CHECK_NE(kNullAddress, address);
|
||||||
|
|
||||||
|
// TODO(ishell): implement RelocInfo::set_target_off_heap_target()
|
||||||
|
if (RelocInfo::OffHeapTargetIsCodedSpecially()) {
|
||||||
|
Address location_of_branch_data = rinfo->pc();
|
||||||
|
Assembler::deserialization_set_special_target_at(location_of_branch_data,
|
||||||
|
host, address);
|
||||||
|
} else {
|
||||||
|
WriteUnalignedValue(rinfo->target_address_address(), address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UnalignedSlot Deserializer::ReadRepeatedObject(UnalignedSlot current,
|
UnalignedSlot Deserializer::ReadRepeatedObject(UnalignedSlot current,
|
||||||
int repeat_count) {
|
int repeat_count) {
|
||||||
CHECK_LE(2, repeat_count);
|
CHECK_LE(2, repeat_count);
|
||||||
MaybeObject object;
|
|
||||||
// We are reading to a location outside of JS heap, so pass NEW_SPACE to
|
HeapObject object = ReadObject();
|
||||||
// avoid triggering write barriers.
|
|
||||||
bool filled = ReadData(UnalignedSlot(&object), UnalignedSlot(&object + 1),
|
|
||||||
NEW_SPACE, kNullAddress);
|
|
||||||
CHECK(filled);
|
|
||||||
DCHECK(HAS_HEAP_OBJECT_TAG(object.ptr()));
|
|
||||||
DCHECK(!Heap::InYoungGeneration(object));
|
DCHECK(!Heap::InYoungGeneration(object));
|
||||||
for (int i = 0; i < repeat_count; i++) {
|
for (int i = 0; i < repeat_count; i++) {
|
||||||
// Repeated values are not subject to the write barrier so we don't need
|
// Repeated values are not subject to the write barrier so we don't need
|
||||||
// to trigger it.
|
// to trigger it.
|
||||||
UnalignedCopy(current, object);
|
UnalignedCopy(current, object.ptr());
|
||||||
current.Advance();
|
current.Advance();
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
@ -549,55 +653,17 @@ bool Deserializer::ReadData(UnalignedSlot current, UnalignedSlot limit,
|
|||||||
// Find an external reference and write a pointer to it in the current
|
// Find an external reference and write a pointer to it in the current
|
||||||
// code object.
|
// code object.
|
||||||
case kExternalReference + kFromCode + kStartOfObject:
|
case kExternalReference + kFromCode + kStartOfObject:
|
||||||
current = ReadExternalReferenceCase(kFromCode, current,
|
UNREACHABLE();
|
||||||
current_object_address);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kInternalReferenceEncoded:
|
case kInternalReferenceEncoded:
|
||||||
case kInternalReference: {
|
case kInternalReference: {
|
||||||
// Internal reference address is not encoded via skip, but by offset
|
UNREACHABLE();
|
||||||
// from code entry.
|
|
||||||
int pc_offset = source_.GetInt();
|
|
||||||
int target_offset = source_.GetInt();
|
|
||||||
Code code = Code::cast(HeapObject::FromAddress(current_object_address));
|
|
||||||
DCHECK(0 <= pc_offset && pc_offset <= code->raw_instruction_size());
|
|
||||||
DCHECK(0 <= target_offset &&
|
|
||||||
target_offset <= code->raw_instruction_size());
|
|
||||||
Address pc = code->entry() + pc_offset;
|
|
||||||
Address target = code->entry() + target_offset;
|
|
||||||
Assembler::deserialization_set_target_internal_reference_at(
|
|
||||||
pc, target,
|
|
||||||
data == kInternalReference ? RelocInfo::INTERNAL_REFERENCE
|
|
||||||
: RelocInfo::INTERNAL_REFERENCE_ENCODED);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case kOffHeapTarget: {
|
case kOffHeapTarget: {
|
||||||
DCHECK(FLAG_embedded_builtins);
|
UNREACHABLE();
|
||||||
int skip = source_.GetInt();
|
|
||||||
int builtin_index = source_.GetInt();
|
|
||||||
DCHECK(Builtins::IsBuiltinId(builtin_index));
|
|
||||||
|
|
||||||
current.Advance(skip);
|
|
||||||
|
|
||||||
CHECK_NOT_NULL(isolate->embedded_blob());
|
|
||||||
EmbeddedData d = EmbeddedData::FromBlob();
|
|
||||||
Address address = d.InstructionStartOfBuiltin(builtin_index);
|
|
||||||
CHECK_NE(kNullAddress, address);
|
|
||||||
|
|
||||||
if (RelocInfo::OffHeapTargetIsCodedSpecially()) {
|
|
||||||
Address location_of_branch_data = current.address();
|
|
||||||
int skip = Assembler::deserialization_special_target_size(
|
|
||||||
location_of_branch_data);
|
|
||||||
Assembler::deserialization_set_special_target_at(
|
|
||||||
location_of_branch_data,
|
|
||||||
Code::cast(HeapObject::FromAddress(current_object_address)),
|
|
||||||
address);
|
|
||||||
current.Advance(skip);
|
|
||||||
} else {
|
|
||||||
UnalignedCopy(current, address);
|
|
||||||
current.Advance();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,7 +678,7 @@ bool Deserializer::ReadData(UnalignedSlot current, UnalignedSlot limit,
|
|||||||
|
|
||||||
case kDeferred: {
|
case kDeferred: {
|
||||||
// Deferred can only occur right after the heap object header.
|
// Deferred can only occur right after the heap object header.
|
||||||
DCHECK_EQ(current.address(), current_object_address + kPointerSize);
|
DCHECK_EQ(current.address(), current_object_address + kTaggedSize);
|
||||||
HeapObject obj = HeapObject::FromAddress(current_object_address);
|
HeapObject obj = HeapObject::FromAddress(current_object_address);
|
||||||
// If the deferred object is a map, its instance type may be used
|
// If the deferred object is a map, its instance type may be used
|
||||||
// during deserialization. Initialize it with a temporary value.
|
// during deserialization. Initialize it with a temporary value.
|
||||||
@ -638,10 +704,17 @@ bool Deserializer::ReadData(UnalignedSlot current, UnalignedSlot limit,
|
|||||||
// Deserialize raw code directly into the body of the code object.
|
// Deserialize raw code directly into the body of the code object.
|
||||||
// Do not move current.
|
// Do not move current.
|
||||||
case kVariableRawCode: {
|
case kVariableRawCode: {
|
||||||
|
// VariableRawCode can only occur right after the heap object header.
|
||||||
|
DCHECK_EQ(current.address(), current_object_address + kTaggedSize);
|
||||||
int size_in_bytes = source_.GetInt();
|
int size_in_bytes = source_.GetInt();
|
||||||
source_.CopyRaw(
|
source_.CopyRaw(
|
||||||
reinterpret_cast<byte*>(current_object_address + Code::kDataStart),
|
reinterpret_cast<byte*>(current_object_address + Code::kDataStart),
|
||||||
size_in_bytes);
|
size_in_bytes);
|
||||||
|
ReadCodeObjectBody(source_space, current_object_address);
|
||||||
|
// Set current to the code object end.
|
||||||
|
current.Advance(Code::kDataStart - HeapObject::kHeaderSize +
|
||||||
|
size_in_bytes);
|
||||||
|
CHECK_EQ(current, limit);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,8 +736,6 @@ bool Deserializer::ReadData(UnalignedSlot current, UnalignedSlot limit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case kApiReference: {
|
case kApiReference: {
|
||||||
int skip = source_.GetInt();
|
|
||||||
current.Advance(skip);
|
|
||||||
uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
|
uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
|
||||||
Address address;
|
Address address;
|
||||||
if (isolate->api_external_references()) {
|
if (isolate->api_external_references()) {
|
||||||
@ -790,23 +861,12 @@ bool Deserializer::ReadData(UnalignedSlot current, UnalignedSlot limit,
|
|||||||
|
|
||||||
UnalignedSlot Deserializer::ReadExternalReferenceCase(
|
UnalignedSlot Deserializer::ReadExternalReferenceCase(
|
||||||
HowToCode how, UnalignedSlot current, Address current_object_address) {
|
HowToCode how, UnalignedSlot current, Address current_object_address) {
|
||||||
int skip = source_.GetInt();
|
|
||||||
current.Advance(skip);
|
|
||||||
uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
|
uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
|
||||||
Address address = external_reference_table_->address(reference_id);
|
Address address = external_reference_table_->address(reference_id);
|
||||||
|
|
||||||
if (how == kFromCode) {
|
DCHECK_EQ(how, kPlain);
|
||||||
Address location_of_branch_data = current.address();
|
UnalignedCopy(current, address);
|
||||||
int skip =
|
current.Advance();
|
||||||
Assembler::deserialization_special_target_size(location_of_branch_data);
|
|
||||||
Assembler::deserialization_set_special_target_at(
|
|
||||||
location_of_branch_data,
|
|
||||||
Code::cast(HeapObject::FromAddress(current_object_address)), address);
|
|
||||||
current.Advance(skip);
|
|
||||||
} else {
|
|
||||||
UnalignedCopy(current, address);
|
|
||||||
current.Advance();
|
|
||||||
}
|
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -824,71 +884,39 @@ UnalignedSlot Deserializer::ReadDataCase(Isolate* isolate,
|
|||||||
? HeapObjectReferenceType::WEAK
|
? HeapObjectReferenceType::WEAK
|
||||||
: HeapObjectReferenceType::STRONG;
|
: HeapObjectReferenceType::STRONG;
|
||||||
|
|
||||||
if (where == kNewObject && how == kPlain && within == kStartOfObject) {
|
if (where == kNewObject) {
|
||||||
heap_object = ReadObject(space_number);
|
heap_object = ReadObject(space_number);
|
||||||
emit_write_barrier = (space_number == NEW_SPACE);
|
emit_write_barrier = (space_number == NEW_SPACE);
|
||||||
|
} else if (where == kBackref) {
|
||||||
|
emit_write_barrier = (space_number == NEW_SPACE);
|
||||||
|
heap_object = GetBackReferencedObject(data & kSpaceMask);
|
||||||
|
} else if (where == kBackrefWithSkip) {
|
||||||
|
int skip = source_.GetInt();
|
||||||
|
current.Advance(skip);
|
||||||
|
emit_write_barrier = (space_number == NEW_SPACE);
|
||||||
|
heap_object = GetBackReferencedObject(data & kSpaceMask);
|
||||||
|
} else if (where == kRootArray) {
|
||||||
|
int id = source_.GetInt();
|
||||||
|
RootIndex root_index = static_cast<RootIndex>(id);
|
||||||
|
heap_object = HeapObject::cast(isolate->root(root_index));
|
||||||
|
emit_write_barrier = Heap::InYoungGeneration(heap_object);
|
||||||
|
hot_objects_.Add(heap_object);
|
||||||
|
} else if (where == kReadOnlyObjectCache) {
|
||||||
|
int cache_index = source_.GetInt();
|
||||||
|
heap_object =
|
||||||
|
HeapObject::cast(isolate->read_only_object_cache()->at(cache_index));
|
||||||
|
DCHECK(!Heap::InYoungGeneration(heap_object));
|
||||||
|
emit_write_barrier = false;
|
||||||
|
} else if (where == kPartialSnapshotCache) {
|
||||||
|
int cache_index = source_.GetInt();
|
||||||
|
heap_object =
|
||||||
|
HeapObject::cast(isolate->partial_snapshot_cache()->at(cache_index));
|
||||||
|
emit_write_barrier = Heap::InYoungGeneration(heap_object);
|
||||||
} else {
|
} else {
|
||||||
if (where == kNewObject) {
|
DCHECK_EQ(where, kAttachedReference);
|
||||||
heap_object = ReadObject(space_number);
|
int index = source_.GetInt();
|
||||||
emit_write_barrier = (space_number == NEW_SPACE);
|
heap_object = *attached_objects_[index];
|
||||||
} else if (where == kBackref) {
|
emit_write_barrier = Heap::InYoungGeneration(heap_object);
|
||||||
emit_write_barrier = (space_number == NEW_SPACE);
|
|
||||||
heap_object = GetBackReferencedObject(data & kSpaceMask);
|
|
||||||
} else if (where == kBackrefWithSkip) {
|
|
||||||
int skip = source_.GetInt();
|
|
||||||
current.Advance(skip);
|
|
||||||
emit_write_barrier = (space_number == NEW_SPACE);
|
|
||||||
heap_object = GetBackReferencedObject(data & kSpaceMask);
|
|
||||||
} else if (where == kRootArray) {
|
|
||||||
int id = source_.GetInt();
|
|
||||||
RootIndex root_index = static_cast<RootIndex>(id);
|
|
||||||
heap_object = HeapObject::cast(isolate->root(root_index));
|
|
||||||
emit_write_barrier = Heap::InYoungGeneration(heap_object);
|
|
||||||
hot_objects_.Add(heap_object);
|
|
||||||
} else if (where == kReadOnlyObjectCache) {
|
|
||||||
int cache_index = source_.GetInt();
|
|
||||||
heap_object =
|
|
||||||
HeapObject::cast(isolate->read_only_object_cache()->at(cache_index));
|
|
||||||
DCHECK(!Heap::InYoungGeneration(heap_object));
|
|
||||||
emit_write_barrier = false;
|
|
||||||
} else if (where == kPartialSnapshotCache) {
|
|
||||||
int cache_index = source_.GetInt();
|
|
||||||
heap_object =
|
|
||||||
HeapObject::cast(isolate->partial_snapshot_cache()->at(cache_index));
|
|
||||||
emit_write_barrier = Heap::InYoungGeneration(heap_object);
|
|
||||||
} else {
|
|
||||||
DCHECK_EQ(where, kAttachedReference);
|
|
||||||
int index = source_.GetInt();
|
|
||||||
heap_object = *attached_objects_[index];
|
|
||||||
emit_write_barrier = Heap::InYoungGeneration(heap_object);
|
|
||||||
}
|
|
||||||
if (how == kFromCode) {
|
|
||||||
Address value;
|
|
||||||
if (within == kInnerPointer) {
|
|
||||||
if (heap_object->IsCode()) {
|
|
||||||
value = Code::cast(heap_object)->raw_instruction_start();
|
|
||||||
} else {
|
|
||||||
value = Cell::cast(heap_object)->ValueAddress();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
value = heap_object->ptr();
|
|
||||||
}
|
|
||||||
DCHECK_EQ(reference_type, HeapObjectReferenceType::STRONG);
|
|
||||||
Address location_of_branch_data = current.address();
|
|
||||||
int skip = Assembler::deserialization_special_target_size(
|
|
||||||
location_of_branch_data);
|
|
||||||
Assembler::deserialization_set_special_target_at(
|
|
||||||
location_of_branch_data,
|
|
||||||
Code::cast(HeapObject::FromAddress(current_object_address)), value);
|
|
||||||
current.Advance(skip);
|
|
||||||
// Nothing else to be done in this case.
|
|
||||||
DCHECK(!write_barrier_needed);
|
|
||||||
return current;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
DCHECK_EQ(how, kPlain);
|
|
||||||
DCHECK_EQ(within, kStartOfObject);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
HeapObjectReference heap_object_ref =
|
HeapObjectReference heap_object_ref =
|
||||||
reference_type == HeapObjectReferenceType::STRONG
|
reference_type == HeapObjectReferenceType::STRONG
|
||||||
|
@ -136,8 +136,19 @@ class Deserializer : public SerializerDeserializer {
|
|||||||
inline UnalignedSlot ReadExternalReferenceCase(
|
inline UnalignedSlot ReadExternalReferenceCase(
|
||||||
HowToCode how, UnalignedSlot current, Address current_object_address);
|
HowToCode how, UnalignedSlot current, Address current_object_address);
|
||||||
|
|
||||||
|
HeapObject ReadObject();
|
||||||
HeapObject ReadObject(int space_number);
|
HeapObject ReadObject(int space_number);
|
||||||
|
void ReadCodeObjectBody(int space_number, Address code_object_address);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void VisitCodeTarget(Code host, RelocInfo* rinfo);
|
||||||
|
void VisitEmbeddedPointer(Code host, RelocInfo* rinfo);
|
||||||
|
void VisitRuntimeEntry(Code host, RelocInfo* rinfo);
|
||||||
|
void VisitExternalReference(Code host, RelocInfo* rinfo);
|
||||||
|
void VisitInternalReference(Code host, RelocInfo* rinfo);
|
||||||
|
void VisitOffHeapTarget(Code host, RelocInfo* rinfo);
|
||||||
|
|
||||||
|
private:
|
||||||
UnalignedSlot ReadRepeatedObject(UnalignedSlot current, int repeat_count);
|
UnalignedSlot ReadRepeatedObject(UnalignedSlot current, int repeat_count);
|
||||||
|
|
||||||
// Special handling for serialized code like hooking up internalized strings.
|
// Special handling for serialized code like hooking up internalized strings.
|
||||||
|
@ -147,12 +147,8 @@ bool Serializer::SerializeHotObject(HeapObject obj, HowToCode how_to_code,
|
|||||||
obj->ShortPrint();
|
obj->ShortPrint();
|
||||||
PrintF("\n");
|
PrintF("\n");
|
||||||
}
|
}
|
||||||
if (skip != 0) {
|
// TODO(ishell): remove kHotObjectWithSkip
|
||||||
sink_.Put(kHotObjectWithSkip + index, "HotObjectWithSkip");
|
sink_.Put(kHotObject + index, "HotObject");
|
||||||
sink_.PutInt(skip, "HotObjectSkipDistance");
|
|
||||||
} else {
|
|
||||||
sink_.Put(kHotObject + index, "HotObject");
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,13 +178,8 @@ bool Serializer::SerializeBackReference(HeapObject obj, HowToCode how_to_code,
|
|||||||
|
|
||||||
PutAlignmentPrefix(obj);
|
PutAlignmentPrefix(obj);
|
||||||
AllocationSpace space = reference.space();
|
AllocationSpace space = reference.space();
|
||||||
if (skip == 0) {
|
// TODO(ishell): remove kBackrefWithSkip
|
||||||
sink_.Put(kBackref + how_to_code + where_to_point + space, "BackRef");
|
sink_.Put(kBackref + how_to_code + where_to_point + space, "BackRef");
|
||||||
} else {
|
|
||||||
sink_.Put(kBackrefWithSkip + how_to_code + where_to_point + space,
|
|
||||||
"BackRefWithSkip");
|
|
||||||
sink_.PutInt(skip, "BackRefSkipDistance");
|
|
||||||
}
|
|
||||||
PutBackReference(obj, reference);
|
PutBackReference(obj, reference);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -219,12 +210,8 @@ void Serializer::PutRoot(RootIndex root, HeapObject object,
|
|||||||
if (how_to_code == kPlain && where_to_point == kStartOfObject &&
|
if (how_to_code == kPlain && where_to_point == kStartOfObject &&
|
||||||
root_index < kNumberOfRootArrayConstants &&
|
root_index < kNumberOfRootArrayConstants &&
|
||||||
!Heap::InYoungGeneration(object)) {
|
!Heap::InYoungGeneration(object)) {
|
||||||
if (skip == 0) {
|
// TODO(ishell): remove kRootArrayConstantsWithSkip
|
||||||
sink_.Put(kRootArrayConstants + root_index, "RootConstant");
|
sink_.Put(kRootArrayConstants + root_index, "RootConstant");
|
||||||
} else {
|
|
||||||
sink_.Put(kRootArrayConstantsWithSkip + root_index, "RootConstant");
|
|
||||||
sink_.PutInt(skip, "SkipInPutRoot");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
FlushSkip(skip);
|
FlushSkip(skip);
|
||||||
sink_.Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
|
sink_.Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
|
||||||
@ -735,7 +722,8 @@ void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
|
|||||||
|
|
||||||
void Serializer::ObjectSerializer::VisitEmbeddedPointer(Code host,
|
void Serializer::ObjectSerializer::VisitEmbeddedPointer(Code host,
|
||||||
RelocInfo* rinfo) {
|
RelocInfo* rinfo) {
|
||||||
int skip = SkipTo(rinfo->target_address_address());
|
// TODO(ishell): remove skip parameter from bytecode.
|
||||||
|
int skip = 0;
|
||||||
HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
|
HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
|
||||||
Object object = rinfo->target_object();
|
Object object = rinfo->target_object();
|
||||||
serializer_->SerializeObject(HeapObject::cast(object), how_to_code,
|
serializer_->SerializeObject(HeapObject::cast(object), how_to_code,
|
||||||
@ -745,7 +733,12 @@ void Serializer::ObjectSerializer::VisitEmbeddedPointer(Code host,
|
|||||||
|
|
||||||
void Serializer::ObjectSerializer::VisitExternalReference(Foreign host,
|
void Serializer::ObjectSerializer::VisitExternalReference(Foreign host,
|
||||||
Address* p) {
|
Address* p) {
|
||||||
int skip = SkipTo(reinterpret_cast<Address>(p));
|
// TODO(ishell): handle gap between map field and payload field
|
||||||
|
// once we shrink kTaggedSize.
|
||||||
|
STATIC_ASSERT(static_cast<int>(Foreign::kForeignAddressOffset) ==
|
||||||
|
static_cast<int>(HeapObject::kHeaderSize));
|
||||||
|
DCHECK_EQ(0, SkipTo(reinterpret_cast<Address>(p)));
|
||||||
|
|
||||||
Address target = *p;
|
Address target = *p;
|
||||||
auto encoded_reference = serializer_->EncodeExternalReference(target);
|
auto encoded_reference = serializer_->EncodeExternalReference(target);
|
||||||
if (encoded_reference.is_from_api()) {
|
if (encoded_reference.is_from_api()) {
|
||||||
@ -753,14 +746,12 @@ void Serializer::ObjectSerializer::VisitExternalReference(Foreign host,
|
|||||||
} else {
|
} else {
|
||||||
sink_->Put(kExternalReference + kPlain + kStartOfObject, "ExternalRef");
|
sink_->Put(kExternalReference + kPlain + kStartOfObject, "ExternalRef");
|
||||||
}
|
}
|
||||||
sink_->PutInt(skip, "SkipB4ExternalRef");
|
|
||||||
sink_->PutInt(encoded_reference.index(), "reference index");
|
sink_->PutInt(encoded_reference.index(), "reference index");
|
||||||
bytes_processed_so_far_ += kSystemPointerSize;
|
bytes_processed_so_far_ += kSystemPointerSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Serializer::ObjectSerializer::VisitExternalReference(Code host,
|
void Serializer::ObjectSerializer::VisitExternalReference(Code host,
|
||||||
RelocInfo* rinfo) {
|
RelocInfo* rinfo) {
|
||||||
int skip = SkipTo(rinfo->target_address_address());
|
|
||||||
Address target = rinfo->target_external_reference();
|
Address target = rinfo->target_external_reference();
|
||||||
auto encoded_reference = serializer_->EncodeExternalReference(target);
|
auto encoded_reference = serializer_->EncodeExternalReference(target);
|
||||||
if (encoded_reference.is_from_api()) {
|
if (encoded_reference.is_from_api()) {
|
||||||
@ -771,7 +762,6 @@ void Serializer::ObjectSerializer::VisitExternalReference(Code host,
|
|||||||
sink_->Put(kExternalReference + how_to_code + kStartOfObject,
|
sink_->Put(kExternalReference + how_to_code + kStartOfObject,
|
||||||
"ExternalRef");
|
"ExternalRef");
|
||||||
}
|
}
|
||||||
sink_->PutInt(skip, "SkipB4ExternalRef");
|
|
||||||
DCHECK_NE(target, kNullAddress); // Code does not reference null.
|
DCHECK_NE(target, kNullAddress); // Code does not reference null.
|
||||||
sink_->PutInt(encoded_reference.index(), "reference index");
|
sink_->PutInt(encoded_reference.index(), "reference index");
|
||||||
bytes_processed_so_far_ += rinfo->target_address_size();
|
bytes_processed_so_far_ += rinfo->target_address_size();
|
||||||
@ -802,15 +792,8 @@ void Serializer::ObjectSerializer::VisitInternalReference(Code host,
|
|||||||
|
|
||||||
void Serializer::ObjectSerializer::VisitRuntimeEntry(Code host,
|
void Serializer::ObjectSerializer::VisitRuntimeEntry(Code host,
|
||||||
RelocInfo* rinfo) {
|
RelocInfo* rinfo) {
|
||||||
int skip = SkipTo(rinfo->target_address_address());
|
// We no longer serialize code that contains runtime entries.
|
||||||
HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
|
UNREACHABLE();
|
||||||
Address target = rinfo->target_address();
|
|
||||||
auto encoded_reference = serializer_->EncodeExternalReference(target);
|
|
||||||
DCHECK(!encoded_reference.is_from_api());
|
|
||||||
sink_->Put(kExternalReference + how_to_code + kStartOfObject, "ExternalRef");
|
|
||||||
sink_->PutInt(skip, "SkipB4ExternalRef");
|
|
||||||
sink_->PutInt(encoded_reference.index(), "reference index");
|
|
||||||
bytes_processed_so_far_ += rinfo->target_address_size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Serializer::ObjectSerializer::VisitOffHeapTarget(Code host,
|
void Serializer::ObjectSerializer::VisitOffHeapTarget(Code host,
|
||||||
@ -824,48 +807,18 @@ void Serializer::ObjectSerializer::VisitOffHeapTarget(Code host,
|
|||||||
Code target = InstructionStream::TryLookupCode(serializer_->isolate(), addr);
|
Code target = InstructionStream::TryLookupCode(serializer_->isolate(), addr);
|
||||||
CHECK(Builtins::IsIsolateIndependentBuiltin(target));
|
CHECK(Builtins::IsIsolateIndependentBuiltin(target));
|
||||||
|
|
||||||
int skip = SkipTo(rinfo->target_address_address());
|
|
||||||
sink_->Put(kOffHeapTarget, "OffHeapTarget");
|
sink_->Put(kOffHeapTarget, "OffHeapTarget");
|
||||||
sink_->PutInt(skip, "SkipB4OffHeapTarget");
|
|
||||||
sink_->PutInt(target->builtin_index(), "builtin index");
|
sink_->PutInt(target->builtin_index(), "builtin index");
|
||||||
bytes_processed_so_far_ += rinfo->target_address_size();
|
bytes_processed_so_far_ += rinfo->target_address_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class CompareRelocInfo {
|
|
||||||
public:
|
|
||||||
bool operator()(RelocInfo x, RelocInfo y) {
|
|
||||||
// Everything that does not use target_address_address will compare equal.
|
|
||||||
Address x_num = 0;
|
|
||||||
Address y_num = 0;
|
|
||||||
if (x.HasTargetAddressAddress()) x_num = x.target_address_address();
|
|
||||||
if (y.HasTargetAddressAddress()) y_num = y.target_address_address();
|
|
||||||
return x_num > y_num;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void Serializer::ObjectSerializer::VisitRelocInfo(RelocIterator* it) {
|
|
||||||
std::priority_queue<RelocInfo, std::vector<RelocInfo>, CompareRelocInfo>
|
|
||||||
reloc_queue;
|
|
||||||
for (; !it->done(); it->next()) {
|
|
||||||
reloc_queue.push(*it->rinfo());
|
|
||||||
}
|
|
||||||
while (!reloc_queue.empty()) {
|
|
||||||
RelocInfo rinfo = reloc_queue.top();
|
|
||||||
reloc_queue.pop();
|
|
||||||
rinfo.Visit(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Serializer::ObjectSerializer::VisitCodeTarget(Code host,
|
void Serializer::ObjectSerializer::VisitCodeTarget(Code host,
|
||||||
RelocInfo* rinfo) {
|
RelocInfo* rinfo) {
|
||||||
#ifdef V8_TARGET_ARCH_ARM
|
#ifdef V8_TARGET_ARCH_ARM
|
||||||
DCHECK(!RelocInfo::IsRelativeCodeTarget(rinfo->rmode()));
|
DCHECK(!RelocInfo::IsRelativeCodeTarget(rinfo->rmode()));
|
||||||
#endif
|
#endif
|
||||||
int skip = SkipTo(rinfo->target_address_address());
|
// TODO(ishell): remove skip parameter from bytecode.
|
||||||
|
int skip = 0;
|
||||||
Code object = Code::GetCodeFromTargetAddress(rinfo->target_address());
|
Code object = Code::GetCodeFromTargetAddress(rinfo->target_address());
|
||||||
serializer_->SerializeObject(object, kFromCode, kInnerPointer, skip);
|
serializer_->SerializeObject(object, kFromCode, kInnerPointer, skip);
|
||||||
bytes_processed_so_far_ += rinfo->target_address_size();
|
bytes_processed_so_far_ += rinfo->target_address_size();
|
||||||
|
@ -227,10 +227,7 @@ class Serializer : public SerializerDeserializer {
|
|||||||
bool ObjectIsBytecodeHandler(HeapObject obj) const;
|
bool ObjectIsBytecodeHandler(HeapObject obj) const;
|
||||||
|
|
||||||
static inline void FlushSkip(SnapshotByteSink* sink, int skip) {
|
static inline void FlushSkip(SnapshotByteSink* sink, int skip) {
|
||||||
if (skip != 0) {
|
// TODO(ishell): remove kSkip and friends as they are no longer needed.
|
||||||
sink->Put(kSkip, "SkipFromSerializeObject");
|
|
||||||
sink->PutInt(skip, "SkipDistanceFromSerializeObject");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void FlushSkip(int skip) { FlushSkip(&sink_, skip); }
|
inline void FlushSkip(int skip) { FlushSkip(&sink_, skip); }
|
||||||
@ -335,8 +332,6 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
|
|||||||
void VisitCodeTarget(Code host, RelocInfo* target) override;
|
void VisitCodeTarget(Code host, RelocInfo* target) override;
|
||||||
void VisitRuntimeEntry(Code host, RelocInfo* reloc) override;
|
void VisitRuntimeEntry(Code host, RelocInfo* reloc) override;
|
||||||
void VisitOffHeapTarget(Code host, RelocInfo* target) override;
|
void VisitOffHeapTarget(Code host, RelocInfo* target) override;
|
||||||
// Relocation info needs to be visited sorted by target_address_address.
|
|
||||||
void VisitRelocInfo(RelocIterator* it) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SerializePrologue(AllocationSpace space, int size, Map map);
|
void SerializePrologue(AllocationSpace space, int size, Map map);
|
||||||
|
Loading…
Reference in New Issue
Block a user