Commit 9c75acec authored by Clemens Backes's avatar Clemens Backes Committed by V8 LUCI CQ

Reland "[codegen] Reduce size of safepoint table fields"

This is a reland of f68242bc, with
fixes for UBSan (double-fixed, actually).

Original change's description:
> [codegen] Reduce size of safepoint table fields
>
> Code objects are often small and do not use the full integer range of PC
> offsets and deoptimization indexes. Reducing the size of these fields to
> the required size per table reduces the overall size of safepoint tables
> by roughly 25%.
>
> R=jkummerow@chromium.org
>
> Bug: v8:12401
> Change-Id: Ie6889a70782f5510436a1d05d31d17aac0bfec6e
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3306556
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Commit-Queue: Clemens Backes <clemensb@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#78216}

Bug: v8:12401
Cq-Include-Trybots: luci.v8.try:v8_linux64_ubsan_rel_ng
Change-Id: I2aa7f6448afd3350b0cc3d09a0f4ac18fcab0928
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3310806Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78244}
parent b891858c
......@@ -80,7 +80,7 @@ void SafepointTable::Print(std::ostream& os) const {
for (int index = 0; index < length_; index++) {
SafepointEntry entry = GetEntry(index);
os << reinterpret_cast<const void*>(instruction_start_ + entry.pc()) << " "
<< std::setw(6) << std::hex << entry.pc();
<< std::setw(6) << std::hex << entry.pc() << std::dec;
if (!entry.tagged_slots().empty()) {
os << " slots (sp->fp): ";
......@@ -163,21 +163,49 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int tagged_slots_size) {
assembler->RecordComment(";;; Safepoint table.");
offset_ = assembler->pc_offset();
// Compute the number of bytes for tagged slots per safepoint entry.
// Compute the required sizes of the fields.
int used_register_indexes = 0;
STATIC_ASSERT(SafepointEntry::kNoTrampolinePC == -1);
int max_pc = -1;
STATIC_ASSERT(SafepointEntry::kNoDeoptIndex == -1);
int max_deopt_index = -1;
for (const EntryBuilder& entry : entries_) {
used_register_indexes |= entry.register_indexes;
max_pc = std::max(max_pc, std::max(entry.pc, entry.trampoline));
max_deopt_index = std::max(max_deopt_index, entry.deopt_index);
}
// Derive the bytes and bools for the entry configuration from the values.
auto value_to_bytes = [](int value) {
DCHECK_LE(0, value);
if (value == 0) return 0;
if (value <= 0xff) return 1;
if (value <= 0xffff) return 2;
if (value <= 0xffffff) return 3;
return 4;
};
bool has_deopt_data = max_deopt_index != -1;
int register_indexes_size = value_to_bytes(used_register_indexes);
// Add 1 so all values are non-negative.
int pc_size = value_to_bytes(max_pc + 1);
int deopt_index_size = value_to_bytes(max_deopt_index + 1);
int tagged_slots_bytes =
RoundUp(tagged_slots_size, kBitsPerByte) >> kBitsPerByteLog2;
bool has_deopt_data =
std::any_of(entries_.begin(), entries_.end(), [](auto& entry) {
return entry.deopt_index != SafepointEntry::kNoDeoptIndex;
});
bool has_register_indexes =
std::any_of(entries_.begin(), entries_.end(),
[](auto& entry) { return entry.register_indexes != 0; });
(tagged_slots_size + kBitsPerByte - 1) / kBitsPerByte;
// Add a CHECK to ensure we never overflow the space in the bitfield, even for
// huge functions which might not be covered by tests.
CHECK(SafepointTable::RegisterIndexesSizeField::is_valid(
register_indexes_size) &&
SafepointTable::PcSizeField::is_valid(pc_size) &&
SafepointTable::DeoptIndexSizeField::is_valid(deopt_index_size) &&
SafepointTable::TaggedSlotsBytesField::is_valid(tagged_slots_bytes));
uint32_t entry_configuration =
SafepointTable::TaggedSlotsBytesField::encode(tagged_slots_bytes) |
SafepointTable::HasDeoptDataField::encode(has_deopt_data) |
SafepointTable::HasRegisterIndexesField::encode(has_register_indexes);
SafepointTable::RegisterIndexesSizeField::encode(register_indexes_size) |
SafepointTable::PcSizeField::encode(pc_size) |
SafepointTable::DeoptIndexSizeField::encode(deopt_index_size) |
SafepointTable::TaggedSlotsBytesField::encode(tagged_slots_bytes);
// Emit the table header.
STATIC_ASSERT(SafepointTable::kLengthOffset == 0 * kIntSize);
......@@ -187,16 +215,20 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int tagged_slots_size) {
assembler->dd(length);
assembler->dd(entry_configuration);
auto emit_bytes = [assembler](int value, int bytes) {
DCHECK_LE(0, value);
for (; bytes > 0; --bytes, value >>= 8) assembler->db(value);
DCHECK_EQ(0, value);
};
// Emit entries, sorted by pc offsets.
for (const EntryBuilder& entry : entries_) {
assembler->dd(entry.pc);
emit_bytes(entry.pc, pc_size);
if (has_deopt_data) {
assembler->dd(entry.deopt_index);
assembler->dd(entry.trampoline);
}
if (has_register_indexes) {
assembler->dd(entry.register_indexes);
// Add 1 so all values are non-negative.
emit_bytes(entry.deopt_index + 1, deopt_index_size);
emit_bytes(entry.trampoline + 1, pc_size);
}
emit_bytes(entry.register_indexes, register_indexes_size);
}
// Emit bitmaps of tagged stack slots.
......
......@@ -109,20 +109,18 @@ class SafepointTable {
Address entry_ptr =
safepoint_table_address_ + kHeaderSize + index * entry_size();
int pc = base::Memory<int>(entry_ptr);
entry_ptr += kPcSize;
int pc = read_bytes(&entry_ptr, pc_size());
int deopt_index = SafepointEntry::kNoDeoptIndex;
int trampoline_pc = SafepointEntry::kNoTrampolinePC;
if (has_deopt_data()) {
deopt_index = base::Memory<int>(entry_ptr);
trampoline_pc = base::Memory<int>(entry_ptr + kIntSize);
entry_ptr += kDeoptDataSize;
}
int tagged_register_indexes = 0;
if (has_register_indexes()) {
tagged_register_indexes = base::Memory<int>(entry_ptr);
entry_ptr += kRegisterIndexesSize;
deopt_index = read_bytes(&entry_ptr, deopt_index_size()) - 1;
trampoline_pc = read_bytes(&entry_ptr, pc_size()) - 1;
DCHECK(deopt_index >= 0 || deopt_index == SafepointEntry::kNoDeoptIndex);
DCHECK(trampoline_pc >= 0 ||
trampoline_pc == SafepointEntry::kNoTrampolinePC);
}
int tagged_register_indexes =
read_bytes(&entry_ptr, register_indexes_size());
// Entry bits start after the the vector of entries (thus the pc offset of
// the non-existing entry after the last one).
......@@ -147,21 +145,20 @@ class SafepointTable {
static constexpr int kEntryConfigurationOffset = kLengthOffset + kIntSize;
static constexpr int kHeaderSize = kEntryConfigurationOffset + kUInt32Size;
// An entry consists of the pc, plus optional deopt data (deopt index and
// trampoline PC), plus optional register indexes.
static constexpr int kPcSize = kIntSize;
static constexpr int kDeoptDataSize = 2 * kIntSize;
static constexpr int kRegisterIndexesSize = kIntSize;
using TaggedSlotsBytesField = base::BitField<int, 0, 30>;
using HasDeoptDataField = TaggedSlotsBytesField::Next<bool, 1>;
using HasRegisterIndexesField = HasDeoptDataField::Next<bool, 1>;
using HasDeoptDataField = base::BitField<bool, 0, 1>;
using RegisterIndexesSizeField = HasDeoptDataField::Next<int, 3>;
using PcSizeField = RegisterIndexesSizeField::Next<int, 3>;
using DeoptIndexSizeField = PcSizeField::Next<int, 3>;
// In 22 bits, we can encode up to 4M bytes, corresponding to 32M frame slots,
// which is 128MB on 32-bit and 256MB on 64-bit systems. The stack size is
// limited to a bit below 1MB anyway (see FLAG_stack_size).
using TaggedSlotsBytesField = DeoptIndexSizeField::Next<int, 22>;
SafepointTable(Address instruction_start, Address safepoint_table_address);
int entry_size() const {
return kPcSize + (has_deopt_data() ? kDeoptDataSize : 0) +
(has_register_indexes() ? kRegisterIndexesSize : 0);
int deopt_data_size = has_deopt_data() ? pc_size() + deopt_index_size() : 0;
return pc_size() + deopt_data_size + register_indexes_size();
}
int tagged_slots_bytes() const {
......@@ -170,8 +167,20 @@ class SafepointTable {
bool has_deopt_data() const {
return HasDeoptDataField::decode(entry_configuration_);
}
bool has_register_indexes() const {
return HasRegisterIndexesField::decode(entry_configuration_);
int pc_size() const { return PcSizeField::decode(entry_configuration_); }
int deopt_index_size() const {
return DeoptIndexSizeField::decode(entry_configuration_);
}
int register_indexes_size() const {
return RegisterIndexesSizeField::decode(entry_configuration_);
}
static int read_bytes(Address* ptr, int bytes) {
uint32_t result = 0;
for (int b = 0; b < bytes; ++b, ++*ptr) {
result |= uint32_t{*reinterpret_cast<uint8_t*>(*ptr)} << (8 * b);
}
return static_cast<int>(result);
}
DISALLOW_GARBAGE_COLLECTION(no_gc_)
......
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