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 604927 : bool SafepointEntry::HasRegisters() const {
19 : DCHECK(is_valid());
20 : DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
21 : const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
22 1814781 : for (int i = 0; i < num_reg_bytes; i++) {
23 1209854 : 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 :
38 2762125 : SafepointTable::SafepointTable(Code* code) {
39 : DCHECK(code->is_turbofanned());
40 2762125 : code_ = code;
41 5524250 : Address header = code->instruction_start() + code->safepoint_table_offset();
42 2762125 : length_ = Memory::uint32_at(header + kLengthOffset);
43 2762125 : entry_size_ = Memory::uint32_at(header + kEntrySizeOffset);
44 2762125 : pc_and_deoptimization_indexes_ = header + kHeaderSize;
45 2762125 : entries_ = pc_and_deoptimization_indexes_ + (length_ * kFixedEntrySize);
46 : DCHECK_GT(entry_size_, 0);
47 : STATIC_ASSERT(SafepointEntry::DeoptimizationIndexField::kMax ==
48 : Safepoint::kNoDeoptimizationIndex);
49 2762125 : }
50 :
51 29354 : unsigned SafepointTable::find_return_pc(unsigned pc_offset) {
52 52420 : for (unsigned i = 0; i < length(); i++) {
53 26210 : if (GetTrampolinePcOffset(i) == static_cast<int>(pc_offset)) {
54 3144 : return GetPcOffset(i);
55 23066 : } else if (GetPcOffset(i) == pc_offset) {
56 : return pc_offset;
57 : }
58 : }
59 0 : UNREACHABLE();
60 : return 0;
61 : }
62 :
63 5517962 : SafepointEntry SafepointTable::FindEntry(Address pc) const {
64 2758981 : unsigned pc_offset = static_cast<unsigned>(pc - code_->instruction_start());
65 : // We use kMaxUInt32 as sentinel value, so check that we don't hit that.
66 : DCHECK_NE(kMaxUInt32, pc_offset);
67 : unsigned len = length();
68 : // If pc == kMaxUInt32, then this entry covers all call sites in the function.
69 2776681 : if (len == 1 && GetPcOffset(0) == kMaxUInt32) return GetEntry(0);
70 21876791 : for (unsigned i = 0; i < len; i++) {
71 : // TODO(kasperl): Replace the linear search with binary search.
72 46662101 : if (GetPcOffset(i) == pc_offset ||
73 22034480 : GetTrampolinePcOffset(i) == static_cast<int>(pc_offset)) {
74 : return GetEntry(i);
75 : }
76 : }
77 0 : UNREACHABLE();
78 : return SafepointEntry();
79 : }
80 :
81 :
82 0 : void SafepointTable::PrintEntry(unsigned index,
83 : std::ostream& os) const { // NOLINT
84 : disasm::NameConverter converter;
85 : SafepointEntry entry = GetEntry(index);
86 : uint8_t* bits = entry.bits();
87 :
88 : // Print the stack slot bits.
89 0 : if (entry_size_ > 0) {
90 : DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
91 : const int first = kNumSafepointRegisters >> kBitsPerByteLog2;
92 0 : int last = entry_size_ - 1;
93 0 : for (int i = first; i < last; i++) PrintBits(os, bits[i], kBitsPerByte);
94 0 : int last_bits = code_->stack_slots() - ((last - first) * kBitsPerByte);
95 0 : PrintBits(os, bits[last], last_bits);
96 :
97 : // Print the registers (if any).
98 0 : if (!entry.HasRegisters()) return;
99 0 : for (int j = 0; j < kNumSafepointRegisters; j++) {
100 0 : if (entry.HasRegisterAt(j)) {
101 0 : os << " | " << converter.NameOfCPURegister(j);
102 : }
103 : }
104 : }
105 : }
106 :
107 :
108 0 : void SafepointTable::PrintBits(std::ostream& os, // NOLINT
109 : uint8_t byte, int digits) {
110 : DCHECK(digits >= 0 && digits <= kBitsPerByte);
111 0 : for (int i = 0; i < digits; i++) {
112 0 : os << (((byte & (1 << i)) == 0) ? "0" : "1");
113 : }
114 0 : }
115 :
116 :
117 0 : void Safepoint::DefinePointerRegister(Register reg, Zone* zone) {
118 0 : registers_->Add(reg.code(), zone);
119 0 : }
120 :
121 :
122 4710795 : Safepoint SafepointTableBuilder::DefineSafepoint(
123 : Assembler* assembler,
124 : Safepoint::Kind kind,
125 : int arguments,
126 : Safepoint::DeoptMode deopt_mode) {
127 : DCHECK_GE(arguments, 0);
128 : DeoptimizationInfo info;
129 9421590 : info.pc = assembler->pc_offset();
130 4710795 : info.arguments = arguments;
131 4710795 : info.has_doubles = (kind & Safepoint::kWithDoubles);
132 4710795 : info.trampoline = -1;
133 4710795 : deoptimization_info_.Add(info, zone_);
134 6687882 : deopt_index_list_.Add(Safepoint::kNoDeoptimizationIndex, zone_);
135 4710747 : if (deopt_mode == Safepoint::kNoLazyDeopt) {
136 1977066 : last_lazy_safepoint_ = deopt_index_list_.length();
137 : }
138 9421537 : indexes_.Add(new(zone_) ZoneList<int>(8, zone_), zone_);
139 4710774 : registers_.Add((kind & Safepoint::kWithRegisters)
140 0 : ? new (zone_) ZoneList<int>(4, zone_)
141 : : nullptr,
142 14132322 : zone_);
143 9421560 : return Safepoint(indexes_.last(), registers_.last());
144 : }
145 :
146 :
147 2733718 : void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) {
148 13668580 : while (last_lazy_safepoint_ < deopt_index_list_.length()) {
149 10934857 : deopt_index_list_[last_lazy_safepoint_++] = index;
150 : }
151 2733718 : }
152 :
153 1300545 : unsigned SafepointTableBuilder::GetCodeOffset() const {
154 : DCHECK(emitted_);
155 1300545 : return offset_;
156 : }
157 :
158 2733716 : int SafepointTableBuilder::UpdateDeoptimizationInfo(int pc, int trampoline,
159 : int start) {
160 : int index = -1;
161 11703380 : for (int i = start; i < deoptimization_info_.length(); i++) {
162 20288774 : if (static_cast<int>(deoptimization_info_[i].pc) == pc) {
163 : index = i;
164 : break;
165 : }
166 : }
167 2733716 : CHECK_GE(index, 0);
168 : DCHECK(index < deoptimization_info_.length());
169 2733716 : deoptimization_info_[index].trampoline = trampoline;
170 2733716 : return index;
171 : }
172 :
173 1301308 : void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
174 1301308 : RemoveDuplicates();
175 :
176 : // Make sure the safepoint table is properly aligned. Pad with nops.
177 1301357 : assembler->Align(kIntSize);
178 1301374 : assembler->RecordComment(";;; Safepoint table.");
179 2602718 : offset_ = assembler->pc_offset();
180 :
181 : // Take the register bits into account.
182 1301359 : bits_per_entry += kNumSafepointRegisters;
183 :
184 : // Compute the number of bytes per safepoint entry.
185 : int bytes_per_entry =
186 1301359 : RoundUp(bits_per_entry, kBitsPerByte) >> kBitsPerByteLog2;
187 :
188 : // Emit the table header.
189 14036154 : int length = deoptimization_info_.length();
190 1301359 : assembler->dd(length);
191 1301287 : assembler->dd(bytes_per_entry);
192 :
193 : // Emit sorted table of pc offsets together with deoptimization indexes.
194 5546392 : for (int i = 0; i < length; i++) {
195 4244917 : assembler->dd(deoptimization_info_[i].pc);
196 : assembler->dd(EncodeExceptPC(deoptimization_info_[i],
197 12734808 : deopt_index_list_[i]));
198 4244942 : assembler->dd(deoptimization_info_[i].trampoline);
199 : }
200 :
201 : // Emit table of bitmaps.
202 1301475 : ZoneList<uint8_t> bits(bytes_per_entry, zone_);
203 5546372 : for (int i = 0; i < length; i++) {
204 20230453 : ZoneList<int>* indexes = indexes_[i];
205 8489903 : ZoneList<int>* registers = registers_[i];
206 : bits.Clear();
207 4244908 : bits.AddBlock(0, bytes_per_entry, zone_);
208 :
209 : // Run through the registers (if any).
210 : DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
211 4244997 : if (registers == nullptr) {
212 : const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
213 8489832 : for (int j = 0; j < num_reg_bytes; j++) {
214 16979664 : bits[j] = SafepointTable::kNoRegisters;
215 : }
216 : } else {
217 87 : for (int j = 0; j < registers->length(); j++) {
218 0 : int index = registers->at(j);
219 : DCHECK(index >= 0 && index < kNumSafepointRegisters);
220 0 : int byte_index = index >> kBitsPerByteLog2;
221 0 : int bit_index = index & (kBitsPerByte - 1);
222 0 : bits[byte_index] |= (1 << bit_index);
223 : }
224 : }
225 :
226 : // Run through the indexes and build a bitmap.
227 19236277 : for (int j = 0; j < indexes->length(); j++) {
228 14991280 : int index = bits_per_entry - 1 - indexes->at(j);
229 7495640 : int byte_index = index >> kBitsPerByteLog2;
230 7495640 : int bit_index = index & (kBitsPerByte - 1);
231 14991280 : bits[byte_index] |= (1U << bit_index);
232 : }
233 :
234 : // Emit the bitmap for the current entry.
235 14717272 : for (int k = 0; k < bytes_per_entry; k++) {
236 29434600 : assembler->db(bits[k]);
237 : }
238 : }
239 1301464 : emitted_ = true;
240 1301464 : }
241 :
242 :
243 0 : uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info,
244 : unsigned index) {
245 : uint32_t encoding = SafepointEntry::DeoptimizationIndexField::encode(index);
246 8489872 : encoding |= SafepointEntry::ArgumentsField::encode(info.arguments);
247 8489872 : encoding |= SafepointEntry::SaveDoublesField::encode(info.has_doubles);
248 0 : return encoding;
249 : }
250 :
251 1301272 : void SafepointTableBuilder::RemoveDuplicates() {
252 : // If the table contains more than one entry, and all entries are identical
253 : // (except for the pc), replace the whole table by a single entry with pc =
254 : // kMaxUInt32. This especially compacts the table for wasm code without tagged
255 : // pointers and without deoptimization info.
256 :
257 1476667 : int length = deoptimization_info_.length();
258 : DCHECK_EQ(length, deopt_index_list_.length());
259 : DCHECK_EQ(length, indexes_.length());
260 : DCHECK_EQ(length, registers_.length());
261 :
262 1301272 : if (length < 2) return;
263 :
264 : // Check that all entries (1, length] are identical to entry 0.
265 496785 : for (int i = 1; i < length; ++i) {
266 867617 : if (!IsIdenticalExceptForPc(0, i)) return;
267 : }
268 :
269 : // If we get here, all entries were identical. Rewind all lists to just one
270 : // entry, and set the pc to kMaxUInt32.
271 : deoptimization_info_.Rewind(1);
272 : deopt_index_list_.Rewind(1);
273 : indexes_.Rewind(1);
274 : registers_.Rewind(1);
275 175395 : deoptimization_info_[0].pc = kMaxUInt32;
276 : }
277 :
278 867623 : bool SafepointTableBuilder::IsIdenticalExceptForPc(int index1,
279 : int index2) const {
280 867623 : DeoptimizationInfo& deopt_info_1 = deoptimization_info_[index1];
281 : DeoptimizationInfo& deopt_info_2 = deoptimization_info_[index2];
282 867623 : if (deopt_info_1.arguments != deopt_info_2.arguments) return false;
283 867653 : if (deopt_info_1.has_doubles != deopt_info_2.has_doubles) return false;
284 :
285 2602962 : if (deopt_index_list_[index1] != deopt_index_list_[index2]) return false;
286 :
287 1614333 : ZoneList<int>* indexes1 = indexes_[index1];
288 1076222 : ZoneList<int>* indexes2 = indexes_[index2];
289 538111 : if (indexes1->length() != indexes2->length()) return false;
290 44751 : for (int i = 0; i < indexes1->length(); ++i) {
291 97500 : if (indexes1->at(i) != indexes2->at(i)) return false;
292 : }
293 :
294 993642 : ZoneList<int>* registers1 = registers_[index1];
295 496821 : ZoneList<int>* registers2 = registers_[index2];
296 496821 : if (registers1) {
297 0 : if (!registers2) return false;
298 0 : if (registers1->length() != registers2->length()) return false;
299 0 : for (int i = 0; i < registers1->length(); ++i) {
300 0 : if (registers1->at(i) != registers2->at(i)) return false;
301 : }
302 496821 : } else if (registers2) {
303 : return false;
304 : }
305 :
306 496782 : return true;
307 : }
308 :
309 : } // namespace internal
310 : } // namespace v8
|