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 1016933 : bool SafepointEntry::HasRegisters() const {
19 : DCHECK(is_valid());
20 : DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
21 : const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
22 3050799 : for (int i = 0; i < num_reg_bytes; i++) {
23 2033866 : 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 11942 : 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 2868575 : has_deopt_(has_deopt) {
43 2868575 : Address header = instruction_start_ + safepoint_table_offset;
44 2868575 : length_ = Memory<uint32_t>(header + kLengthOffset);
45 5737150 : entry_size_ = Memory<uint32_t>(header + kEntrySizeOffset);
46 2868575 : pc_and_deoptimization_indexes_ = header + kHeaderSize;
47 2868575 : entries_ = pc_and_deoptimization_indexes_ + (length_ * kFixedEntrySize);
48 : DCHECK_GT(entry_size_, 0);
49 : STATIC_ASSERT(SafepointEntry::DeoptimizationIndexField::kMax ==
50 : Safepoint::kNoDeoptimizationIndex);
51 11942 : }
52 :
53 2856633 : SafepointTable::SafepointTable(Code code)
54 : : SafepointTable(code->InstructionStart(), code->safepoint_table_offset(),
55 5713266 : code->stack_slots(), true) {}
56 :
57 52812 : unsigned SafepointTable::find_return_pc(unsigned pc_offset) {
58 93364 : for (unsigned i = 0; i < length(); i++) {
59 46682 : if (GetTrampolinePcOffset(i) == static_cast<int>(pc_offset)) {
60 6130 : return GetPcOffset(i);
61 40552 : } else if (GetPcOffset(i) == pc_offset) {
62 : return pc_offset;
63 : }
64 : }
65 0 : UNREACHABLE();
66 : return 0;
67 : }
68 :
69 5724890 : SafepointEntry SafepointTable::FindEntry(Address pc) const {
70 2862445 : 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 2862445 : CHECK_GT(len, 0);
75 : // If pc == kMaxUInt32, then this entry covers all call sites in the function.
76 2893132 : if (len == 1 && GetPcOffset(0) == kMaxUInt32) return GetEntry(0);
77 34704778 : for (unsigned i = 0; i < len; i++) {
78 : // TODO(kasperl): Replace the linear search with binary search.
79 75115784 : if (GetPcOffset(i) == pc_offset ||
80 34710275 : (has_deopt_ &&
81 34710275 : 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 6290706 : Safepoint SafepointTableBuilder::DefineSafepoint(
130 : Assembler* assembler,
131 : Safepoint::Kind kind,
132 : Safepoint::DeoptMode deopt_mode) {
133 : deoptimization_info_.push_back(
134 21972555 : DeoptimizationInfo(zone_, assembler->pc_offset(), kind));
135 6290672 : if (deopt_mode == Safepoint::kNoLazyDeopt) {
136 3100471 : last_lazy_safepoint_ = deoptimization_info_.size();
137 : }
138 : DeoptimizationInfo& new_info = deoptimization_info_.back();
139 6290672 : return Safepoint(new_info.indexes, new_info.registers);
140 : }
141 :
142 3190186 : void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) {
143 15950928 : for (auto it = deoptimization_info_.Find(last_lazy_safepoint_);
144 : it != deoptimization_info_.end(); it++, last_lazy_safepoint_++) {
145 3190185 : it->deopt_index = index;
146 : }
147 3190186 : }
148 :
149 2654720 : unsigned SafepointTableBuilder::GetCodeOffset() const {
150 : DCHECK(emitted_);
151 2654720 : return offset_;
152 : }
153 :
154 2928030 : int SafepointTableBuilder::UpdateDeoptimizationInfo(int pc, int trampoline,
155 : int start) {
156 : int index = start;
157 15145960 : for (auto it = deoptimization_info_.Find(start);
158 : it != deoptimization_info_.end(); it++, index++) {
159 : if (static_cast<int>(it->pc) == pc) {
160 2928030 : it->trampoline = trampoline;
161 2928030 : return index;
162 : }
163 : }
164 0 : UNREACHABLE();
165 : }
166 :
167 2711512 : void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
168 2711512 : RemoveDuplicates();
169 :
170 : // Make sure the safepoint table is properly aligned. Pad with nops.
171 2711541 : assembler->Align(kIntSize);
172 2711506 : assembler->RecordComment(";;; Safepoint table.");
173 2711564 : offset_ = assembler->pc_offset();
174 :
175 : // Take the register bits into account.
176 2711564 : bits_per_entry += kNumSafepointRegisters;
177 :
178 : // Compute the number of bytes per safepoint entry.
179 : int bytes_per_entry =
180 2711564 : 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 2711564 : int length = static_cast<int>(deoptimization_info_.size());
187 2711564 : assembler->dd(length);
188 2711604 : 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 11008740 : for (const DeoptimizationInfo& info : deoptimization_info_) {
197 5585370 : assembler->dd(info.pc);
198 5585378 : assembler->dd(EncodeExceptPC(info));
199 5585414 : assembler->dd(info.trampoline);
200 : }
201 :
202 : // Emit table of bitmaps.
203 2711718 : ZoneVector<uint8_t> bits(bytes_per_entry, 0, zone_);
204 11008519 : for (const DeoptimizationInfo& info : deoptimization_info_) {
205 5585294 : ZoneChunkList<int>* indexes = info.indexes;
206 5585294 : 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 5585294 : if (registers == nullptr) {
212 : const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
213 11170684 : for (int j = 0; j < num_reg_bytes; j++) {
214 22341368 : 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 42457158 : for (int idx : *indexes) {
227 15643285 : int index = bits_per_entry - 1 - idx;
228 15643285 : int byte_index = index >> kBitsPerByteLog2;
229 15643285 : int bit_index = index & (kBitsPerByte - 1);
230 31286570 : bits[byte_index] |= (1U << bit_index);
231 : }
232 :
233 : // Emit the bitmap for the current entry.
234 21539727 : for (int k = 0; k < bytes_per_entry; k++) {
235 43079304 : assembler->db(bits[k]);
236 : }
237 : }
238 2711650 : emitted_ = true;
239 2711650 : }
240 :
241 0 : uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info) {
242 5585378 : return SafepointEntry::DeoptimizationIndexField::encode(info.deopt_index) |
243 11170756 : SafepointEntry::SaveDoublesField::encode(info.has_doubles);
244 : }
245 :
246 2711431 : 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 2886854 : if (deoptimization_info_.size() < 2) return;
253 :
254 : // Check that all entries (1, size] are identical to entry 0.
255 617171 : const DeoptimizationInfo& first_info = deoptimization_info_.front();
256 1751893 : for (auto it = deoptimization_info_.Find(1); it != deoptimization_info_.end();
257 : it++) {
258 959277 : 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 175445 : deoptimization_info_.Rewind(1);
264 175423 : deoptimization_info_.front().pc = kMaxUInt32;
265 : }
266 :
267 959304 : bool SafepointTableBuilder::IsIdenticalExceptForPc(
268 : const DeoptimizationInfo& info1, const DeoptimizationInfo& info2) const {
269 959304 : if (info1.has_doubles != info2.has_doubles) return false;
270 959322 : if (info1.deopt_index != info2.deopt_index) return false;
271 :
272 1249722 : ZoneChunkList<int>* indexes1 = info1.indexes;
273 1249722 : ZoneChunkList<int>* indexes2 = info2.indexes;
274 624861 : if (indexes1->size() != indexes2->size()) return false;
275 522153 : if (!std::equal(indexes1->begin(), indexes1->end(), indexes2->begin())) {
276 : return false;
277 : }
278 :
279 517548 : ZoneChunkList<int>* registers1 = info1.registers;
280 517548 : ZoneChunkList<int>* registers2 = info2.registers;
281 517548 : 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 0 : registers2->begin())) {
286 : return false;
287 : }
288 517548 : } else if (registers2) {
289 : return false;
290 : }
291 :
292 : return true;
293 : }
294 :
295 : } // namespace internal
296 178779 : } // namespace v8
|