v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
maglev-safepoint-table.cc
Go to the documentation of this file.
1// Copyright 2022 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <iomanip>
8
11
12namespace v8 {
13namespace internal {
14
16 Tagged<Code> code)
17 : MaglevSafepointTable(code->InstructionStart(isolate, pc),
18 code->safepoint_table_address()) {
19 DCHECK(code->is_maglevved());
20}
21
24 : MaglevSafepointTable(code->InstructionStart(isolate, pc),
25 code->safepoint_table_address()) {
26 DCHECK(code->is_maglevved());
27}
28
30 Address safepoint_table_address)
31 : instruction_start_(instruction_start),
32 safepoint_table_address_(safepoint_table_address),
33 stack_slots_(base::Memory<SafepointTableStackSlotsField_t>(
34 safepoint_table_address + kStackSlotsOffset)),
35 length_(base::Memory<int>(safepoint_table_address + kLengthOffset)),
36 entry_configuration_(base::Memory<uint32_t>(safepoint_table_address +
37 kEntryConfigurationOffset)),
38 num_tagged_slots_(base::Memory<uint32_t>(safepoint_table_address +
39 kNumTaggedSlotsOffset)) {}
40
42 for (int i = 0; i < length(); i++) {
44 if (entry.trampoline_pc() == pc_offset || entry.pc() == pc_offset) {
45 return entry.pc();
46 }
47 }
49}
50
52 int pc_offset = static_cast<int>(pc - instruction_start_);
53
54 // Check if the PC is pointing at a trampoline.
55 if (has_deopt_data()) {
56 for (int i = 0; i < length_; ++i) {
58 int trampoline_pc = GetEntry(i).trampoline_pc();
59 if (trampoline_pc != -1 && trampoline_pc == pc_offset) return entry;
60 if (trampoline_pc > pc_offset) break;
61 }
62 }
63
64 // Try to find an exact pc match.
65 for (int i = 0; i < length_; ++i) {
67 if (entry.pc() == pc_offset) {
68 return entry;
69 }
70 }
71
72 // Return a default entry which has no deopt data and no pushed registers.
73 // This allows us to elide emitting entries for trivial calls.
75 int trampoline_pc = MaglevSafepointEntry::kNoTrampolinePC;
76 uint8_t num_extra_spill_slots = 0;
77 int tagged_register_indexes = 0;
78
80 num_extra_spill_slots, tagged_register_indexes,
81 trampoline_pc);
82}
83
84// static
87 Address pc) {
88 MaglevSafepointTable table(isolate, pc, code);
89 return table.FindEntry(pc);
90}
91
92void MaglevSafepointTable::Print(std::ostream& os) const {
93 os << "Safepoints (stack slots = " << stack_slots_
94 << ", entries = " << length_ << ", byte size = " << byte_size()
95 << ", tagged slots = " << num_tagged_slots_ << ")\n";
96
97 for (int index = 0; index < length_; index++) {
98 MaglevSafepointEntry entry = GetEntry(index);
99 os << reinterpret_cast<const void*>(instruction_start_ + entry.pc()) << " "
100 << std::setw(6) << std::hex << entry.pc() << std::dec;
101
102 os << " num extra spill slots: "
103 << static_cast<int>(entry.num_extra_spill_slots());
104
105 if (entry.tagged_register_indexes() != 0) {
106 os << " registers: ";
107 uint32_t register_bits = entry.tagged_register_indexes();
108 int bits = 32 - base::bits::CountLeadingZeros32(register_bits);
109 for (int j = bits - 1; j >= 0; --j) {
110 os << ((register_bits >> j) & 1);
111 }
112 }
113
114 if (entry.has_deoptimization_index()) {
115 os << " deopt " << std::setw(6) << entry.deoptimization_index()
116 << " trampoline: " << std::setw(6) << std::hex
117 << entry.trampoline_pc();
118 }
119 os << "\n";
120 }
121}
122
125 entries_.push_back(EntryBuilder(assembler->pc_offset_for_safepoint()));
127}
128
130 int trampoline,
131 int start,
132 int deopt_index) {
135 auto it = entries_.Find(start);
136 DCHECK(std::any_of(it, entries_.end(),
137 [pc](auto& entry) { return entry.pc == pc; }));
138 int index = start;
139 while (it->pc != pc) ++it, ++index;
140 it->trampoline = trampoline;
141 it->deopt_index = deopt_index;
142 return index;
143}
144
146#ifdef DEBUG
147 int last_pc = -1;
148 int last_trampoline = -1;
149 for (const EntryBuilder& entry : entries_) {
150 // Entries are ordered by PC.
151 DCHECK_LT(last_pc, entry.pc);
152 last_pc = entry.pc;
153 // Trampoline PCs are increasing, and larger than regular PCs.
154 if (entry.trampoline != MaglevSafepointEntry::kNoTrampolinePC) {
155 DCHECK_LT(last_trampoline, entry.trampoline);
156 DCHECK_LT(entries_.back().pc, entry.trampoline);
157 last_trampoline = entry.trampoline;
158 }
159 // An entry either has trampoline and deopt index, or none of the two.
161 entry.deopt_index == MaglevSafepointEntry::kNoDeoptIndex);
162 }
163#endif // DEBUG
164
165#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64
166 // We cannot emit a const pool within the safepoint table.
167 Assembler::BlockConstPoolScope block_const_pool(assembler);
168#endif
169
170 // Make sure the safepoint table is properly aligned. Pad with nops.
172 assembler->RecordComment(";;; Maglev safepoint table.");
173 set_safepoint_table_offset(assembler->pc_offset());
174
175 // Compute the required sizes of the fields.
176 int used_register_indexes = 0;
177 static_assert(MaglevSafepointEntry::kNoTrampolinePC == -1);
179 static_assert(MaglevSafepointEntry::kNoDeoptIndex == -1);
180 int max_deopt_index = MaglevSafepointEntry::kNoDeoptIndex;
181 for (const EntryBuilder& entry : entries_) {
182 used_register_indexes |= entry.tagged_register_indexes;
183 max_pc = std::max(max_pc, std::max(entry.pc, entry.trampoline));
184 max_deopt_index = std::max(max_deopt_index, entry.deopt_index);
185 }
186
187 // Derive the bytes and bools for the entry configuration from the values.
188 auto value_to_bytes = [](int value) {
189 DCHECK_LE(0, value);
190 if (value == 0) return 0;
191 if (value <= 0xff) return 1;
192 if (value <= 0xffff) return 2;
193 if (value <= 0xffffff) return 3;
194 return 4;
195 };
196 bool has_deopt_data = max_deopt_index != -1;
197 int register_indexes_size = value_to_bytes(used_register_indexes);
198 // Add 1 so all values (including kNoDeoptIndex and kNoTrampolinePC) are
199 // non-negative.
200 static_assert(MaglevSafepointEntry::kNoDeoptIndex == -1);
201 static_assert(MaglevSafepointEntry::kNoTrampolinePC == -1);
202 int pc_size = value_to_bytes(max_pc + 1);
203 int deopt_index_size = value_to_bytes(max_deopt_index + 1);
204
205 // Add a CHECK to ensure we never overflow the space in the bitfield, even for
206 // huge functions which might not be covered by tests.
208 register_indexes_size));
211
212 uint32_t entry_configuration =
215 register_indexes_size) |
218
219 // Emit the table header.
220 static_assert(MaglevSafepointTable::kStackSlotsOffset == 0 * kIntSize);
221 static_assert(MaglevSafepointTable::kLengthOffset == 1 * kIntSize);
222 static_assert(MaglevSafepointTable::kEntryConfigurationOffset ==
223 2 * kIntSize);
224 static_assert(MaglevSafepointTable::kNumTaggedSlotsOffset == 3 * kIntSize);
225 static_assert(MaglevSafepointTable::kHeaderSize == 4 * kIntSize);
226 int length = static_cast<int>(entries_.size());
227 assembler->dd(stack_slots);
228 assembler->dd(length);
229 assembler->dd(entry_configuration);
230 assembler->dd(num_tagged_slots_);
231
232 auto emit_bytes = [assembler](int value, int bytes) {
233 DCHECK_LE(0, value);
234 for (; bytes > 0; --bytes, value >>= 8) assembler->db(value);
235 DCHECK_EQ(0, value);
236 };
237 // Emit entries, sorted by pc offsets.
238 for (const EntryBuilder& entry : entries_) {
239 emit_bytes(entry.pc, pc_size);
240 if (has_deopt_data) {
241 // Add 1 so all values (including kNoDeoptIndex and kNoTrampolinePC) are
242 // non-negative.
243 static_assert(MaglevSafepointEntry::kNoDeoptIndex == -1);
244 static_assert(MaglevSafepointEntry::kNoTrampolinePC == -1);
245 emit_bytes(entry.deopt_index + 1, deopt_index_size);
246 emit_bytes(entry.trampoline + 1, pc_size);
247 }
248 assembler->db(entry.num_extra_spill_slots);
249 emit_bytes(entry.tagged_register_indexes, register_indexes_size);
250 }
251}
252
253} // namespace internal
254} // namespace v8
static constexpr bool is_valid(T value)
Definition bit-field.h:50
static constexpr U encode(T value)
Definition bit-field.h:55
static constexpr int kMetadataAlignment
int UpdateDeoptimizationInfo(int pc, int trampoline, int start, int deopt_index)
V8_EXPORT_PRIVATE void Emit(Assembler *assembler, int stack_slots)
Safepoint DefineSafepoint(Assembler *assembler)
MaglevSafepointEntry FindEntry(Address pc) const
MaglevSafepointTable(Isolate *isolate, Address pc, Tagged< Code > code)
MaglevSafepointEntry GetEntry(int index) const
const SafepointTableStackSlotsField_t stack_slots_
int start
AssemblerT assembler
int pc_offset
base::SmallVector< int32_t, 1 > stack_slots
const int length_
Definition mul-fft.cc:473
constexpr unsigned CountLeadingZeros32(uint32_t value)
Definition bits.h:122
constexpr int kIntSize
Definition globals.h:400
uint32_t SafepointTableStackSlotsField_t
return value
Definition map-inl.h:893
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
const uint8_t * instruction_start_