Line data Source code
1 : // Copyright 2011 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 :
5 : #include "src/safepoint-table.h"
6 :
7 : #include "src/assembler-inl.h"
8 : #include "src/deoptimizer.h"
9 : #include "src/disasm.h"
10 : #include "src/frames-inl.h"
11 : #include "src/macro-assembler.h"
12 : #include "src/ostreams.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 :
18 1222106 : bool SafepointEntry::HasRegisters() const {
19 : DCHECK(is_valid());
20 : DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
21 : const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
22 6110530 : for (int i = 0; i < num_reg_bytes; i++) {
23 2444212 : if (bits_[i] != SafepointTable::kNoRegisters) return true;
24 : }
25 : return false;
26 : }
27 :
28 :
29 0 : bool SafepointEntry::HasRegisterAt(int reg_index) const {
30 : DCHECK(is_valid());
31 : DCHECK(reg_index >= 0 && reg_index < kNumSafepointRegisters);
32 0 : int byte_index = reg_index >> kBitsPerByteLog2;
33 0 : int bit_index = reg_index & (kBitsPerByte - 1);
34 0 : return (bits_[byte_index] & (1 << bit_index)) != 0;
35 : }
36 :
37 12661 : SafepointTable::SafepointTable(Address instruction_start,
38 : size_t safepoint_table_offset,
39 : uint32_t stack_slots, bool has_deopt)
40 : : instruction_start_(instruction_start),
41 : stack_slots_(stack_slots),
42 2870474 : has_deopt_(has_deopt) {
43 2870474 : Address header = instruction_start_ + safepoint_table_offset;
44 2870474 : length_ = Memory<uint32_t>(header + kLengthOffset);
45 5740948 : entry_size_ = Memory<uint32_t>(header + kEntrySizeOffset);
46 2870474 : pc_and_deoptimization_indexes_ = header + kHeaderSize;
47 2870474 : entries_ = pc_and_deoptimization_indexes_ + (length_ * kFixedEntrySize);
48 : DCHECK_GT(entry_size_, 0);
49 : STATIC_ASSERT(SafepointEntry::DeoptimizationIndexField::kMax ==
50 : Safepoint::kNoDeoptimizationIndex);
51 12661 : }
52 :
53 2857813 : SafepointTable::SafepointTable(Code code)
54 : : SafepointTable(code->InstructionStart(), code->safepoint_table_offset(),
55 5715626 : code->stack_slots(), true) {}
56 :
57 6124 : unsigned SafepointTable::find_return_pc(unsigned pc_offset) {
58 87250 : for (unsigned i = 0; i < length(); i++) {
59 46687 : if (GetTrampolinePcOffset(i) == static_cast<int>(pc_offset)) {
60 6124 : return GetPcOffset(i);
61 40563 : } else if (GetPcOffset(i) == pc_offset) {
62 : return pc_offset;
63 : }
64 : }
65 0 : UNREACHABLE();
66 : return 0;
67 : }
68 :
69 2864350 : SafepointEntry SafepointTable::FindEntry(Address pc) const {
70 2864350 : unsigned pc_offset = static_cast<unsigned>(pc - instruction_start_);
71 : // We use kMaxUInt32 as sentinel value, so check that we don't hit that.
72 : DCHECK_NE(kMaxUInt32, pc_offset);
73 : unsigned len = length();
74 2864350 : CHECK_GT(len, 0);
75 : // If pc == kMaxUInt32, then this entry covers all call sites in the function.
76 2890570 : if (len == 1 && GetPcOffset(0) == kMaxUInt32) return GetEntry(0);
77 72101539 : for (unsigned i = 0; i < len; i++) {
78 : // TODO(kasperl): Replace the linear search with binary search.
79 109607698 : if (GetPcOffset(i) == pc_offset ||
80 69277457 : (has_deopt_ &&
81 34627839 : GetTrampolinePcOffset(i) == static_cast<int>(pc_offset))) {
82 : return GetEntry(i);
83 : }
84 : }
85 0 : UNREACHABLE();
86 : return SafepointEntry();
87 : }
88 :
89 :
90 0 : void SafepointTable::PrintEntry(unsigned index,
91 : std::ostream& os) const { // NOLINT
92 : disasm::NameConverter converter;
93 : SafepointEntry entry = GetEntry(index);
94 : uint8_t* bits = entry.bits();
95 :
96 : // Print the stack slot bits.
97 0 : if (entry_size_ > 0) {
98 : DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
99 : const int first = kNumSafepointRegisters >> kBitsPerByteLog2;
100 0 : int last = entry_size_ - 1;
101 0 : for (int i = first; i < last; i++) PrintBits(os, bits[i], kBitsPerByte);
102 0 : int last_bits = stack_slots_ - ((last - first) * kBitsPerByte);
103 0 : PrintBits(os, bits[last], last_bits);
104 :
105 : // Print the registers (if any).
106 0 : if (!entry.HasRegisters()) return;
107 0 : for (int j = 0; j < kNumSafepointRegisters; j++) {
108 0 : if (entry.HasRegisterAt(j)) {
109 0 : os << " | " << converter.NameOfCPURegister(j);
110 : }
111 : }
112 : }
113 : }
114 :
115 :
116 0 : void SafepointTable::PrintBits(std::ostream& os, // NOLINT
117 : uint8_t byte, int digits) {
118 : DCHECK(digits >= 0 && digits <= kBitsPerByte);
119 0 : for (int i = 0; i < digits; i++) {
120 0 : os << (((byte & (1 << i)) == 0) ? "0" : "1");
121 : }
122 0 : }
123 :
124 0 : void Safepoint::DefinePointerRegister(Register reg) {
125 0 : registers_->push_back(reg.code());
126 0 : }
127 :
128 :
129 6450075 : Safepoint SafepointTableBuilder::DefineSafepoint(
130 : Assembler* assembler,
131 : Safepoint::Kind kind,
132 : Safepoint::DeoptMode deopt_mode) {
133 12900654 : deoptimization_info_.push_back(
134 6450241 : DeoptimizationInfo(zone_, assembler->pc_offset(), kind));
135 6450579 : if (deopt_mode == Safepoint::kNoLazyDeopt) {
136 3495309 : last_lazy_safepoint_ = deoptimization_info_.size();
137 : }
138 : DeoptimizationInfo& new_info = deoptimization_info_.back();
139 6450579 : return Safepoint(new_info.indexes, new_info.registers);
140 : }
141 :
142 2955123 : void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) {
143 11820462 : for (auto it = deoptimization_info_.Find(last_lazy_safepoint_);
144 2955108 : it != deoptimization_info_.end(); it++, last_lazy_safepoint_++) {
145 2955108 : it->deopt_index = index;
146 : }
147 2955123 : }
148 :
149 3024537 : unsigned SafepointTableBuilder::GetCodeOffset() const {
150 : DCHECK(emitted_);
151 3024537 : return offset_;
152 : }
153 :
154 2955123 : int SafepointTableBuilder::UpdateDeoptimizationInfo(int pc, int trampoline,
155 : int start) {
156 : int index = start;
157 12341266 : for (auto it = deoptimization_info_.Find(start);
158 : it != deoptimization_info_.end(); it++, index++) {
159 : if (static_cast<int>(it->pc) == pc) {
160 2955123 : it->trampoline = trampoline;
161 2955123 : return index;
162 : }
163 : }
164 0 : UNREACHABLE();
165 : }
166 :
167 3081022 : void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
168 3081022 : RemoveDuplicates();
169 :
170 : // Make sure the safepoint table is properly aligned. Pad with nops.
171 3080692 : assembler->Align(kIntSize);
172 3081022 : assembler->RecordComment(";;; Safepoint table.");
173 3081313 : offset_ = assembler->pc_offset();
174 :
175 : // Take the register bits into account.
176 3081313 : bits_per_entry += kNumSafepointRegisters;
177 :
178 : // Compute the number of bytes per safepoint entry.
179 : int bytes_per_entry =
180 3081313 : RoundUp(bits_per_entry, kBitsPerByte) >> kBitsPerByteLog2;
181 :
182 : // Emit the table header.
183 : STATIC_ASSERT(SafepointTable::kLengthOffset == 0 * kIntSize);
184 : STATIC_ASSERT(SafepointTable::kEntrySizeOffset == 1 * kIntSize);
185 : STATIC_ASSERT(SafepointTable::kHeaderSize == 2 * kIntSize);
186 : int length = static_cast<int>(deoptimization_info_.size());
187 3081313 : assembler->dd(length);
188 3081197 : assembler->dd(bytes_per_entry);
189 :
190 : // Emit sorted table of pc offsets together with additional info (i.e. the
191 : // deoptimization index or arguments count) and trampoline offsets.
192 : STATIC_ASSERT(SafepointTable::kPcOffset == 0 * kIntSize);
193 : STATIC_ASSERT(SafepointTable::kEncodedInfoOffset == 1 * kIntSize);
194 : STATIC_ASSERT(SafepointTable::kTrampolinePcOffset == 2 * kIntSize);
195 : STATIC_ASSERT(SafepointTable::kFixedEntrySize == 3 * kIntSize);
196 9067471 : for (const DeoptimizationInfo& info : deoptimization_info_) {
197 5985068 : assembler->dd(info.pc);
198 5985421 : assembler->dd(EncodeExceptPC(info));
199 5985792 : assembler->dd(info.trampoline);
200 : }
201 :
202 : // Emit table of bitmaps.
203 3082403 : ZoneVector<uint8_t> bits(bytes_per_entry, 0, zone_);
204 9067594 : for (const DeoptimizationInfo& info : deoptimization_info_) {
205 5985278 : ZoneChunkList<int>* indexes = info.indexes;
206 5985278 : ZoneChunkList<int>* registers = info.registers;
207 : std::fill(bits.begin(), bits.end(), 0);
208 :
209 : // Run through the registers (if any).
210 : DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
211 5985278 : if (registers == nullptr) {
212 : const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
213 29929390 : for (int j = 0; j < num_reg_bytes; j++) {
214 23944112 : bits[j] = SafepointTable::kNoRegisters;
215 : }
216 : } else {
217 0 : for (int index : *registers) {
218 : DCHECK(index >= 0 && index < kNumSafepointRegisters);
219 0 : int byte_index = index >> kBitsPerByteLog2;
220 0 : int bit_index = index & (kBitsPerByte - 1);
221 0 : bits[byte_index] |= (1 << bit_index);
222 : }
223 : }
224 :
225 : // Run through the indexes and build a bitmap.
226 37626778 : for (int idx : *indexes) {
227 15820750 : int index = bits_per_entry - 1 - idx;
228 15820750 : int byte_index = index >> kBitsPerByteLog2;
229 15820750 : int bit_index = index & (kBitsPerByte - 1);
230 31641500 : bits[byte_index] |= (1U << bit_index);
231 : }
232 :
233 : // Emit the bitmap for the current entry.
234 51561302 : for (int k = 0; k < bytes_per_entry; k++) {
235 45575496 : assembler->db(bits[k]);
236 : }
237 : }
238 3082316 : emitted_ = true;
239 3082316 : }
240 :
241 0 : uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info) {
242 5985421 : return SafepointEntry::DeoptimizationIndexField::encode(info.deopt_index) |
243 11970842 : SafepointEntry::SaveDoublesField::encode(info.has_doubles);
244 : }
245 :
246 3080666 : void SafepointTableBuilder::RemoveDuplicates() {
247 : // If the table contains more than one entry, and all entries are identical
248 : // (except for the pc), replace the whole table by a single entry with pc =
249 : // kMaxUInt32. This especially compacts the table for wasm code without tagged
250 : // pointers and without deoptimization info.
251 :
252 3080666 : if (deoptimization_info_.size() < 2) return;
253 :
254 : // Check that all entries (1, size] are identical to entry 0.
255 : const DeoptimizationInfo& first_info = deoptimization_info_.front();
256 1219538 : for (auto it = deoptimization_info_.Find(1); it != deoptimization_info_.end();
257 : it++) {
258 1014541 : if (!IsIdenticalExceptForPc(first_info, *it)) return;
259 : }
260 :
261 : // If we get here, all entries were identical. Rewind the list to just one
262 : // entry, and set the pc to kMaxUInt32.
263 : deoptimization_info_.Rewind(1);
264 204997 : deoptimization_info_.front().pc = kMaxUInt32;
265 : }
266 :
267 1014551 : bool SafepointTableBuilder::IsIdenticalExceptForPc(
268 : const DeoptimizationInfo& info1, const DeoptimizationInfo& info2) const {
269 1014551 : if (info1.has_doubles != info2.has_doubles) return false;
270 1014560 : if (info1.deopt_index != info2.deopt_index) return false;
271 :
272 674636 : ZoneChunkList<int>* indexes1 = info1.indexes;
273 674636 : ZoneChunkList<int>* indexes2 = info2.indexes;
274 674636 : if (indexes1->size() != indexes2->size()) return false;
275 570376 : if (!std::equal(indexes1->begin(), indexes1->end(), indexes2->begin())) {
276 : return false;
277 : }
278 :
279 565394 : ZoneChunkList<int>* registers1 = info1.registers;
280 565394 : ZoneChunkList<int>* registers2 = info2.registers;
281 565394 : if (registers1) {
282 0 : if (!registers2) return false;
283 0 : if (registers1->size() != registers2->size()) return false;
284 0 : if (!std::equal(registers1->begin(), registers1->end(),
285 : registers2->begin())) {
286 : return false;
287 : }
288 565394 : } else if (registers2) {
289 : return false;
290 : }
291 :
292 : return true;
293 : }
294 :
295 : } // namespace internal
296 121996 : } // namespace v8
|