Commit 779b0edd authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[code] Move embedded metadata to the .rodata section

The embedded metadata section is the off-heap equivalent to an on-heap
Code object's metadata section. It contains no executable data, thus
.rodata is the natural home for it. Another motivation is that some
platforms do not grant read permissions on the .text section.

Embedded blob stats before:

  EmbeddedData:
    Total size: 1322944
    Data size:  25952
    Code size:  1296992

And after:

  EmbeddedData:
    Total size: 1323372
    Data size:  121452
    Code size:  1201920

(Slight size increase due to additional padding.)

Bug: v8:11036,v8:10707
Change-Id: Ib6b54a7e947966c7bd2fcc1e7e44c85e352f0063
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2502334Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70822}
parent 3640583f
......@@ -199,7 +199,10 @@ void CodeStatistics::CollectCodeCommentStatistics(HeapObject obj,
Isolate* isolate) {
// Bytecode objects do not contain RelocInfo. Only process code objects
// for code comment statistics.
if (!obj.IsCode()) return;
if (!obj.IsCode()) {
DCHECK(obj.IsBytecodeArray());
return;
}
Code code = Code::cast(obj);
CodeCommentsIterator cit(code.code_comments(), code.code_comments_size());
......@@ -212,9 +215,8 @@ void CodeStatistics::CollectCodeCommentStatistics(HeapObject obj,
cit.Next();
}
STATIC_ASSERT(Code::kBodyIsContiguous);
DCHECK(0 <= prev_pc_offset && prev_pc_offset <= code.raw_body_size());
delta += static_cast<int>(code.raw_body_size() - prev_pc_offset);
DCHECK(0 <= prev_pc_offset && prev_pc_offset <= code.InstructionSize());
delta += static_cast<int>(code.InstructionSize() - prev_pc_offset);
EnterComment(isolate, "NoComment", delta);
}
#endif
......
......@@ -119,7 +119,6 @@ MaybeHandle<Code> Factory::CodeBuilder::BuildInternal(
isolate_->heap()->SetBasicBlockProfilingData(new_list);
}
// TODO(jgruber,v8:11036): Distinguish instruction and metadata areas.
STATIC_ASSERT(Code::kOnHeapBodyIsContiguous);
const int object_size = Code::SizeFor(code_desc_.body_size());
......
......@@ -222,11 +222,6 @@ void Code::set_next_code_link(Object value) {
Address Code::raw_body_start() const { return raw_instruction_start(); }
Address Code::BodyStart() const {
STATIC_ASSERT(kBodyIsContiguous);
return InstructionStart();
}
Address Code::raw_body_end() const {
return raw_body_start() + raw_body_size();
}
......@@ -235,19 +230,6 @@ int Code::raw_body_size() const {
return raw_instruction_size() + raw_metadata_size();
}
Address Code::BodyEnd() const {
STATIC_ASSERT(kBodyIsContiguous);
return MetadataEnd();
}
int Code::BodySize() const {
// TODO(jgruber,v8:11036): Update once embedded instructions and metadata are
// separate.
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapInstructionSize() + OffHeapMetadataSize()
: raw_body_size();
}
int Code::InstructionSize() const {
return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapInstructionSize()
: raw_instruction_size();
......@@ -276,7 +258,7 @@ Address Code::raw_metadata_start() const {
}
Address Code::MetadataStart() const {
STATIC_ASSERT(kBodyIsContiguous);
STATIC_ASSERT(kOnHeapBodyIsContiguous);
return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapMetadataStart()
: raw_metadata_start();
}
......@@ -286,13 +268,11 @@ Address Code::raw_metadata_end() const {
}
Address Code::MetadataEnd() const {
STATIC_ASSERT(kBodyIsContiguous);
return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapMetadataEnd()
: raw_metadata_end();
}
int Code::MetadataSize() const {
STATIC_ASSERT(kBodyIsContiguous);
return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapMetadataSize()
: raw_metadata_size();
}
......@@ -547,12 +527,10 @@ bool Code::is_optimized_code() const {
bool Code::is_wasm_code() const { return kind() == CodeKind::WASM_FUNCTION; }
int Code::constant_pool_offset() const {
if (!FLAG_enable_embedded_constant_pool) return code_comments_offset();
return ReadField<int>(kConstantPoolOffsetOffset);
}
void Code::set_constant_pool_offset(int value) {
if (!FLAG_enable_embedded_constant_pool) return;
DCHECK_LE(value, MetadataSize());
WriteField<int>(kConstantPoolOffsetOffset, value);
}
......
......@@ -91,7 +91,6 @@ void Code::FlushICache() const {
void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) {
// Copy code.
// TODO(jgruber,v8:11036): Distinguish instruction and metadata areas.
STATIC_ASSERT(kOnHeapBodyIsContiguous);
CopyBytes(reinterpret_cast<byte*>(raw_instruction_start()), desc.buffer,
static_cast<size_t>(desc.instr_size));
......
......@@ -129,20 +129,16 @@ class Code : public HeapObject {
// | | <-- MS + unwinding_info_offset()
// +--------------------------+ <-- MetadataEnd()
// TODO(jgruber,v8:11036): Update once no longer true for embedded builtins.
// Constants for use in static asserts, stating whether the body is adjacent,
// i.e. instructions and metadata areas are adjacent.
static constexpr bool kOnHeapBodyIsContiguous = true;
static constexpr bool kOffHeapBodyIsContiguous = true;
static constexpr bool kOffHeapBodyIsContiguous = false;
static constexpr bool kBodyIsContiguous =
kOnHeapBodyIsContiguous && kOffHeapBodyIsContiguous;
inline Address raw_body_start() const;
inline Address BodyStart() const;
inline Address raw_body_end() const;
inline Address BodyEnd() const;
inline int raw_body_size() const;
// TODO(jgruber,v8:11036): Replace this once the off-heap instruction and
// metadata areas are separate.
inline int BodySize() const;
inline Address raw_instruction_start() const;
inline Address InstructionStart() const;
......@@ -171,8 +167,7 @@ class Code : public HeapObject {
// The metadata section is aligned to this value.
static constexpr int kMetadataAlignment = kIntSize;
// [safepoint_table_offset]: If {has_safepoint_info()}, the offset where the
// safepoint table starts.
// [safepoint_table_offset]: The offset where the safepoint table starts.
inline int safepoint_table_offset() const { return 0; }
Address SafepointTableAddress() const;
int safepoint_table_size() const;
......@@ -187,9 +182,9 @@ class Code : public HeapObject {
bool has_handler_table() const;
// [constant_pool offset]: Offset of the constant pool.
// Valid for FLAG_enable_embedded_constant_pool only
inline int constant_pool_offset() const;
inline void set_constant_pool_offset(int offset);
inline Address constant_pool() const;
int constant_pool_size() const;
bool has_constant_pool() const;
......@@ -325,9 +320,6 @@ class Code : public HeapObject {
// this is a trampoline to an off-heap builtin.
inline bool is_off_heap_trampoline() const;
// [constant_pool]: The constant pool for this function.
inline Address constant_pool() const;
// Get the safepoint entry for the given pc.
SafepointEntry GetSafepointEntry(Address pc);
......
......@@ -663,6 +663,7 @@ void Deserializer::RelocInfoVisitor::VisitInternalReference(Code host,
// TODO(jgruber,v8:11036): We are being permissive for this DCHECK, but
// consider using raw_instruction_size() instead of raw_body_size() in the
// future.
STATIC_ASSERT(Code::kOnHeapBodyIsContiguous);
DCHECK_LT(static_cast<unsigned>(target_offset),
static_cast<unsigned>(host.raw_body_size()));
Address target = host.entry() + target_offset;
......
......@@ -209,6 +209,7 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
bool saw_unsafe_builtin = false;
uint32_t raw_code_size = 0;
uint32_t raw_data_size = 0;
STATIC_ASSERT(Builtins::kAllBuiltinsAreIsolateIndependent);
for (int i = 0; i < Builtins::builtin_count; i++) {
Code code = builtins->builtin(i);
......@@ -228,16 +229,16 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
uint32_t instruction_size =
static_cast<uint32_t>(code.raw_instruction_size());
uint32_t metadata_size = static_cast<uint32_t>(code.raw_metadata_size());
uint32_t length = instruction_size + metadata_size;
DCHECK_EQ(0, raw_code_size % kCodeAlignment);
layout_descriptions[i].instruction_offset = raw_code_size;
layout_descriptions[i].instruction_length = instruction_size;
layout_descriptions[i].metadata_offset = raw_code_size + instruction_size;
layout_descriptions[i].metadata_offset = raw_data_size;
layout_descriptions[i].metadata_length = metadata_size;
// Align the start of each instruction stream.
raw_code_size += PadAndAlign(length);
// Align the start of each section.
raw_code_size += PadAndAlignCode(instruction_size);
raw_data_size += PadAndAlignData(metadata_size);
}
CHECK_WITH_MSG(
!saw_unsafe_builtin,
......@@ -245,12 +246,15 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
"isolate-dependent code or aliases the off-heap trampoline register. "
"If in doubt, ask jgruber@");
// Allocate space for the code section, value-initialized to 0.
STATIC_ASSERT(RawCodeOffset() == 0);
const uint32_t blob_code_size = RawCodeOffset() + raw_code_size;
uint8_t* const blob_code = new uint8_t[blob_code_size];
uint8_t* const raw_code_start = blob_code + RawCodeOffset();
const uint32_t blob_data_size =
LayoutDescriptionTableOffset() + LayoutDescriptionTableSize();
uint8_t* const blob_data = new uint8_t[blob_data_size];
uint8_t* const blob_code = new uint8_t[blob_code_size]();
// Allocate space for the data section, value-initialized to 0.
STATIC_ASSERT(IsAligned(FixedDataSize(), Code::kMetadataAlignment));
const uint32_t blob_data_size = FixedDataSize() + raw_data_size;
uint8_t* const blob_data = new uint8_t[blob_data_size]();
// Initially zap the entire blob, effectively padding the alignment area
// between two builtins with int3's (on x64/ia32).
......@@ -269,16 +273,30 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
std::memcpy(blob_data + LayoutDescriptionTableOffset(),
layout_descriptions.data(), LayoutDescriptionTableSize());
// Write the raw data section.
// .. and the variable-size data section.
uint8_t* const raw_metadata_start = blob_data + RawMetadataOffset();
STATIC_ASSERT(Builtins::kAllBuiltinsAreIsolateIndependent);
for (int i = 0; i < Builtins::builtin_count; i++) {
Code code = builtins->builtin(i);
uint32_t offset = layout_descriptions[i].metadata_offset;
uint8_t* dst = raw_metadata_start + offset;
DCHECK_LE(RawMetadataOffset() + offset + code.raw_metadata_size(),
blob_data_size);
std::memcpy(dst, reinterpret_cast<uint8_t*>(code.raw_metadata_start()),
code.raw_metadata_size());
}
// .. and the variable-size code section.
uint8_t* const raw_code_start = blob_code + RawCodeOffset();
STATIC_ASSERT(Builtins::kAllBuiltinsAreIsolateIndependent);
for (int i = 0; i < Builtins::builtin_count; i++) {
STATIC_ASSERT(Code::kBodyIsContiguous);
Code code = builtins->builtin(i);
uint32_t offset = layout_descriptions[i].instruction_offset;
uint8_t* dst = raw_code_start + offset;
DCHECK_LE(RawCodeOffset() + offset + code.raw_body_size(), blob_code_size);
std::memcpy(dst, reinterpret_cast<uint8_t*>(code.raw_body_start()),
code.raw_body_size());
DCHECK_LE(RawCodeOffset() + offset + code.raw_instruction_size(),
blob_code_size);
std::memcpy(dst, reinterpret_cast<uint8_t*>(code.raw_instruction_start()),
code.raw_instruction_size());
}
EmbeddedData d(blob_code, blob_code_size, blob_data, blob_data_size);
......@@ -318,10 +336,9 @@ uint32_t EmbeddedData::InstructionSizeOfBuiltin(int i) const {
Address EmbeddedData::MetadataStartOfBuiltin(int i) const {
DCHECK(Builtins::IsBuiltinId(i));
STATIC_ASSERT(Code::kOffHeapBodyIsContiguous);
const struct LayoutDescription* descs = LayoutDescription();
const uint8_t* result = RawCode() + descs[i].metadata_offset;
DCHECK_LT(result, code_ + code_size_);
const uint8_t* result = RawMetadata() + descs[i].metadata_offset;
DCHECK_LE(descs[i].metadata_offset, data_size_);
return reinterpret_cast<Address>(result);
}
......
......@@ -85,10 +85,9 @@ class EmbeddedData final {
// Padded with kCodeAlignment.
// TODO(v8:11045): Consider removing code alignment.
uint32_t PaddedInstructionSizeOfBuiltin(int i) const {
STATIC_ASSERT(Code::kOffHeapBodyIsContiguous);
uint32_t size = InstructionSizeOfBuiltin(i) + MetadataSizeOfBuiltin(i);
uint32_t size = InstructionSizeOfBuiltin(i);
CHECK_NE(size, 0);
return PadAndAlign(size);
return PadAndAlignCode(size);
}
size_t CreateEmbeddedBlobHash() const;
......@@ -129,10 +128,12 @@ class EmbeddedData final {
// [1] hash of embedded-blob-relevant heap objects
// [2] layout description of instruction stream 0
// ... layout descriptions
// [x] metadata section of builtin 0
// ... metadata sections
//
// code:
// [0] instruction stream 0
// ... instruction streams
// [0] instruction section of builtin 0
// ... instruction sections
static constexpr uint32_t kTableSize = Builtins::builtin_count;
static constexpr uint32_t EmbeddedBlobHashOffset() { return 0; }
......@@ -147,6 +148,13 @@ class EmbeddedData final {
static constexpr uint32_t LayoutDescriptionTableSize() {
return sizeof(struct LayoutDescription) * kTableSize;
}
static constexpr uint32_t FixedDataSize() {
return LayoutDescriptionTableOffset() + LayoutDescriptionTableSize();
}
// The variable-size data section starts here.
static constexpr uint32_t RawMetadataOffset() { return FixedDataSize(); }
// Code is in its own dedicated section.
static constexpr uint32_t RawCodeOffset() { return 0; }
private:
......@@ -159,28 +167,35 @@ class EmbeddedData final {
DCHECK_LT(0, data_size);
}
const uint8_t* RawCode() const { return code_ + RawCodeOffset(); }
const LayoutDescription* LayoutDescription() const {
return reinterpret_cast<const struct LayoutDescription*>(
data_ + LayoutDescriptionTableOffset());
}
const uint8_t* RawCode() const { return code_ + RawCodeOffset(); }
const uint8_t* RawMetadata() const { return data_ + RawMetadataOffset(); }
static constexpr int PadAndAlign(int size) {
static constexpr int PadAndAlignCode(int size) {
// Ensure we have at least one byte trailing the actual builtin
// instructions which we can later fill with int3.
return RoundUp<kCodeAlignment>(size + 1);
}
static constexpr int PadAndAlignData(int size) {
// Ensure we have at least one byte trailing the actual builtin
// instructions which we can later fill with int3.
return RoundUp<Code::kMetadataAlignment>(size);
}
void PrintStatistics() const;
// This points to code for builtins. The contents are potentially unreadable
// on platforms that disallow reads from the .text section.
// The code section contains instruction streams. It is guaranteed to have
// execute permissions, and may have read permissions.
const uint8_t* code_;
uint32_t code_size_;
// The data section contains both descriptions of the code section (hashes,
// offsets, sizes) and metadata describing Code objects (see
// Code::MetadataStart()).
// Code::MetadataStart()). It is guaranteed to have read permissions.
const uint8_t* data_;
uint32_t data_size_;
};
......
......@@ -130,9 +130,10 @@ void EmbeddedFileWriter::WriteBuiltinLabels(PlatformEmbeddedFileWriterBase* w,
w->DeclareLabel(name.c_str());
}
void EmbeddedFileWriter::WriteInstructionStreams(
PlatformEmbeddedFileWriterBase* w, const i::EmbeddedData* blob) const {
w->Comment("The embedded blob data starts here. It contains the builtin");
void EmbeddedFileWriter::WriteCodeSection(PlatformEmbeddedFileWriterBase* w,
const i::EmbeddedData* blob) const {
w->Comment(
"The embedded blob code section starts here. It contains the builtin");
w->Comment("instruction streams.");
w->SectionText();
......
......@@ -110,7 +110,7 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
WriteFilePrologue(writer.get());
WriteExternalFilenames(writer.get());
WriteDataSection(writer.get(), blob);
WriteInstructionStreams(writer.get(), blob);
WriteCodeSection(writer.get(), blob);
WriteFileEpilogue(writer.get(), blob);
fclose(fp);
......@@ -185,7 +185,7 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
void WriteBuiltinLabels(PlatformEmbeddedFileWriterBase* w,
std::string name) const;
void WriteInstructionStreams(PlatformEmbeddedFileWriterBase* w,
void WriteCodeSection(PlatformEmbeddedFileWriterBase* w,
const i::EmbeddedData* blob) const;
void WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w,
......
......@@ -4,6 +4,8 @@
#include "src/snapshot/embedded/platform-embedded-file-writer-aix.h"
#include "src/objects/code.h"
namespace v8 {
namespace internal {
......@@ -63,10 +65,12 @@ void PlatformEmbeddedFileWriterAIX::DeclareSymbolGlobal(const char* name) {
}
void PlatformEmbeddedFileWriterAIX::AlignToCodeAlignment() {
STATIC_ASSERT((1 << 5) >= kCodeAlignment);
fprintf(fp_, ".align 5\n");
}
void PlatformEmbeddedFileWriterAIX::AlignToDataAlignment() {
STATIC_ASSERT((1 << 3) >= Code::kMetadataAlignment);
fprintf(fp_, ".align 3\n");
}
......
......@@ -8,6 +8,7 @@
#include <cinttypes>
#include "src/common/globals.h"
#include "src/objects/code.h"
namespace v8 {
namespace internal {
......@@ -73,6 +74,7 @@ void PlatformEmbeddedFileWriterGeneric::DeclareSymbolGlobal(const char* name) {
}
void PlatformEmbeddedFileWriterGeneric::AlignToCodeAlignment() {
STATIC_ASSERT(32 >= kCodeAlignment);
fprintf(fp_, ".balign 32\n");
}
......@@ -81,6 +83,7 @@ void PlatformEmbeddedFileWriterGeneric::AlignToDataAlignment() {
// instructions are used to retrieve v8_Default_embedded_blob_ and/or
// v8_Default_embedded_blob_size_. The generated instructions require the
// load target to be aligned at 8 bytes (2^3).
STATIC_ASSERT(8 >= Code::kMetadataAlignment);
fprintf(fp_, ".balign 8\n");
}
......
......@@ -4,6 +4,8 @@
#include "src/snapshot/embedded/platform-embedded-file-writer-mac.h"
#include "src/objects/code.h"
namespace v8 {
namespace internal {
......@@ -54,6 +56,7 @@ void PlatformEmbeddedFileWriterMac::DeclareSymbolGlobal(const char* name) {
// prevents something along the compilation chain from messing with the
// embedded blob. Using .global here causes embedded blob hash verification
// failures at runtime.
STATIC_ASSERT(32 >= kCodeAlignment);
fprintf(fp_, ".private_extern _%s\n", name);
}
......@@ -62,6 +65,7 @@ void PlatformEmbeddedFileWriterMac::AlignToCodeAlignment() {
}
void PlatformEmbeddedFileWriterMac::AlignToDataAlignment() {
STATIC_ASSERT(8 >= Code::kMetadataAlignment);
fprintf(fp_, ".balign 8\n");
}
......
......@@ -978,6 +978,7 @@ void Serializer::ObjectSerializer::VisitInternalReference(Code host,
// TODO(jgruber,v8:11036): We are being permissive for this DCHECK, but
// consider using raw_instruction_size() instead of raw_body_size() in the
// future.
STATIC_ASSERT(Code::kOnHeapBodyIsContiguous);
DCHECK_LE(target_offset, Handle<Code>::cast(object_)->raw_body_size());
sink_->Put(kInternalReference, "InternalRef");
sink_->PutInt(target_offset, "internal ref value");
......
......@@ -878,11 +878,7 @@ CompilationEnv NativeModule::CreateCompilationEnv() const {
WasmCode* NativeModule::AddCodeForTesting(Handle<Code> code) {
CODE_SPACE_WRITE_SCOPE
// For off-heap builtins, we create a copy of the off-heap instruction stream
// instead of the on-heap code object containing the trampoline. Ensure that
// we do not apply the on-heap reloc info to the off-heap instructions.
const size_t relocation_size =
code->is_off_heap_trampoline() ? 0 : code->relocation_size();
const size_t relocation_size = code->relocation_size();
OwnedVector<byte> reloc_info;
if (relocation_size > 0) {
reloc_info = OwnedVector<byte>::Of(
......@@ -896,14 +892,16 @@ WasmCode* NativeModule::AddCodeForTesting(Handle<Code> code) {
source_pos_table->copy_out(0, source_pos.start(),
source_pos_table->length());
}
STATIC_ASSERT(Code::kBodyIsContiguous);
Vector<const byte> instructions(reinterpret_cast<byte*>(code->BodyStart()),
static_cast<size_t>(code->BodySize()));
CHECK(!code->is_off_heap_trampoline());
STATIC_ASSERT(Code::kOnHeapBodyIsContiguous);
Vector<const byte> instructions(
reinterpret_cast<byte*>(code->raw_body_start()),
static_cast<size_t>(code->raw_body_size()));
const int stack_slots = code->has_safepoint_info() ? code->stack_slots() : 0;
// Metadata offsets in Code objects are relative to the start of the metadata
// section, whereas WasmCode expects offsets relative to InstructionStart.
const int base_offset = code->InstructionSize();
const int base_offset = code->raw_instruction_size();
// TODO(jgruber,v8:8758): Remove this translation. It exists only because
// Code objects contains real offsets but WasmCode expects an offset of 0 to
// mean 'empty'.
......@@ -920,7 +918,7 @@ WasmCode* NativeModule::AddCodeForTesting(Handle<Code> code) {
// Apply the relocation delta by iterating over the RelocInfo.
intptr_t delta = reinterpret_cast<Address>(dst_code_bytes.begin()) -
code->InstructionStart();
code->raw_instruction_start();
int mode_mask =
RelocInfo::kApplyMask | RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL);
auto jump_tables_ref =
......
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