Commit d854d351 authored by jgruber's avatar jgruber Committed by Commit Bot

[builtins] Clear RelocInfo for off-heap trampolines

For technical reasons, we used to serialize off-heap trampolines with a
RelocInfo containing a single OFF_HEAP_TARGET entry. This RelocInfo was
never needed at runtime. It also ended up being somewhat misleading
because printing an embedded code object would show the OFF_HEAP_TARGET
entry (belonging to the trampoline) at the first 'real' instruction.

With this CL, we explicitly serialize an empty byte array as the reloc
info for each off-heap trampoline, i.e. the snapshot will never contain
such off-heap target reloc infos.

Bug: v8:6666, v8:7969
Change-Id: If6fa85a438d093ed5dcea07ce0de1db49a224d28
Reviewed-on: https://chromium-review.googlesource.com/1146643
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54786}
parent 268117f8
......@@ -577,6 +577,17 @@ class RelocInfo {
static constexpr int ModeMask(Mode mode) { return 1 << mode; }
// The mode mask used by GC and serialization Code object iteration.
static constexpr int ModeMaskForIteration() {
return RelocInfo::ModeMask(RelocInfo::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);
}
// Accessors
Address pc() const { return pc_; }
Mode rmode() const { return rmode_; }
......
......@@ -504,18 +504,10 @@ class Code::BodyDescriptor final : public BodyDescriptorBase {
template <typename ObjectVisitor>
static inline void IterateBody(Map* map, HeapObject* obj, ObjectVisitor* v) {
int mode_mask = RelocInfo::ModeMask(RelocInfo::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.
IteratePointers(obj, kRelocationInfoOffset, kDataStart, v);
RelocIterator it(Code::cast(obj), mode_mask);
RelocIterator it(Code::cast(obj), RelocInfo::ModeMaskForIteration());
v->VisitRelocInfo(&it);
}
......
......@@ -152,13 +152,22 @@ Code* BuiltinDeserializer::DeserializeBuiltinRaw(int builtin_id) {
source()->set_position(code_offsets_[builtin_id]);
Object* o = ReadDataSingle();
DCHECK(o->IsCode() && Code::cast(o)->is_builtin());
Code* code = Code::cast(o);
DCHECK(o->IsCode() && code->is_builtin());
// Rewind.
source()->set_position(initial_position);
#ifdef DEBUG
// Off-heap trampolines should not have any attached reloc infos. We clear
// them explicitly during serialization in SerializeContent.
if (code->is_off_heap_trampoline()) {
RelocIterator it(code);
CHECK(it.done());
}
#endif // DEBUG
// Flush the instruction cache.
Code* code = Code::cast(o);
Assembler::FlushICache(code->raw_instruction_start(),
code->raw_instruction_size());
......
......@@ -436,6 +436,50 @@ int32_t Serializer<AllocatorT>::ObjectSerializer::SerializeBackingStore(
return static_cast<int32_t>(reference.off_heap_backing_store_index());
}
template <class AllocatorT>
void Serializer<AllocatorT>::ObjectSerializer::SerializeCode() {
Code* code = Code::cast(object_);
const int size = code->Size();
// For code objects, output raw bytes first.
OutputCode(size);
// Then iterate references.
if (code->is_off_heap_trampoline()) {
// This check ensures that OutputRawData (called as part of VisitPointers)
// would do nothing, and thus it's safe to skip here. We can go ahead and
// SerializeObject.
CHECK_EQ(bytes_processed_so_far_, Code::kRelocationInfoOffset);
// Ensure the Code object layout has not changed in unexpected ways.
STATIC_ASSERT(Code::kRelocationInfoOffset == HeapObject::kHeaderSize);
STATIC_ASSERT(Code::kDeoptimizationDataOffset ==
Code::kRelocationInfoOffset + kPointerSize);
// Fix up an empty RelocInfo for off-heap trampolines by acting as if the
// empty byte array were located at kRelocationInfoOffset.
ByteArray* empty_byte_array =
ReadOnlyRoots(serializer_->isolate()->heap()).empty_byte_array();
serializer_->SerializeObject(empty_byte_array, kPlain, kStartOfObject, 0);
bytes_processed_so_far_ += kPointerSize;
// Then continue body visitation as usual at the next field.
VisitPointers(code,
HeapObject::RawField(code, Code::kDeoptimizationDataOffset),
HeapObject::RawField(code, Code::kDataStart));
// Then iterate embedded references via the reloc info.
RelocIterator it(code, RelocInfo::ModeMaskForIteration());
VisitRelocInfo(&it);
} else {
// Other (non-off-heap-trampoline) code objects iterate references normally.
object_->IterateBody(code->map(), size, this);
}
// Finally skip to the end.
serializer_->FlushSkip(SkipTo(object_->address() + size));
}
template <class AllocatorT>
void Serializer<AllocatorT>::ObjectSerializer::SerializeJSTypedArray() {
JSTypedArray* typed_array = JSTypedArray::cast(object_);
......@@ -712,12 +756,10 @@ void Serializer<AllocatorT>::ObjectSerializer::SerializeContent(Map* map,
int size) {
UnlinkWeakNextScope unlink_weak_next(serializer_->isolate()->heap(), object_);
if (object_->IsCode()) {
// For code objects, output raw bytes first.
OutputCode(size);
// Then iterate references via reloc info.
object_->IterateBody(map, size, this);
// Finally skip to the end.
serializer_->FlushSkip(SkipTo(object_->address() + size));
// Code objects have special iteration logic. Raw bytes are output first,
// then references are visited. Also, we artificially clear the reloc info
// for off-heap trampolines for serialization.
SerializeCode();
} else {
// For other objects, iterate references first.
object_->IterateBody(map, size, this);
......@@ -1005,13 +1047,7 @@ void Serializer<AllocatorT>::ObjectSerializer::OutputCode(int size) {
// To make snapshots reproducible, we make a copy of the code object
// and wipe all pointers in the copy, which we then serialize.
code = serializer_->CopyCode(code);
int mode_mask = RelocInfo::ModeMask(RelocInfo::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);
const int mode_mask = RelocInfo::ModeMaskForIteration();
for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
rinfo->WipeOut();
......
......@@ -316,6 +316,7 @@ class Serializer<AllocatorT>::ObjectSerializer : public ObjectVisitor {
void OutputCode(int size);
int SkipTo(Address to);
int32_t SerializeBackingStore(void* backing_store, int32_t byte_length);
void SerializeCode();
void SerializeJSTypedArray();
void SerializeJSArrayBuffer();
void SerializeExternalString();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment