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#ifndef V8_SAFEPOINT_TABLE_H_
6#define V8_SAFEPOINT_TABLE_H_
7
8#include "src/allocation.h"
9#include "src/assert-scope.h"
10#include "src/utils.h"
11#include "src/v8memory.h"
12#include "src/zone/zone-chunk-list.h"
13#include "src/zone/zone.h"
14
15namespace v8 {
16namespace internal {
17
18class Register;
19
20class SafepointEntry {
21 public:
22 SafepointEntry() : info_(0), bits_(nullptr), trampoline_pc_(-1) {}
23
24 SafepointEntry(unsigned info, uint8_t* bits, int trampoline_pc)
25 : info_(info), bits_(bits), trampoline_pc_(trampoline_pc) {
26 DCHECK(is_valid());
27 }
28
29 bool is_valid() const { return bits_ != nullptr; }
30
31 bool Equals(const SafepointEntry& other) const {
32 return info_ == other.info_ && bits_ == other.bits_;
33 }
34
35 void Reset() {
36 info_ = 0;
37 bits_ = nullptr;
38 }
39
40 int trampoline_pc() { return trampoline_pc_; }
41
42 static const int kSaveDoublesFieldBits = 1;
43 static const int kDeoptIndexBits = 32 - kSaveDoublesFieldBits;
44
45 class DeoptimizationIndexField : public BitField<int, 0, kDeoptIndexBits> {};
46 class SaveDoublesField
47 : public BitField<bool, DeoptimizationIndexField::kNext,
48 kSaveDoublesFieldBits> {};
49
50 int deoptimization_index() const {
51 DCHECK(is_valid() && has_deoptimization_index());
52 return DeoptimizationIndexField::decode(info_);
53 }
54
55 bool has_deoptimization_index() const {
56 DCHECK(is_valid());
57 return DeoptimizationIndexField::decode(info_) !=
58 DeoptimizationIndexField::kMax;
59 }
60
61 bool has_doubles() const {
62 DCHECK(is_valid());
63 return SaveDoublesField::decode(info_);
64 }
65
66 uint8_t* bits() {
67 DCHECK(is_valid());
68 return bits_;
69 }
70
71 bool HasRegisters() const;
72 bool HasRegisterAt(int reg_index) const;
73
74 private:
75 unsigned info_;
76 uint8_t* bits_;
77 // It needs to be an integer as it is -1 for eager deoptimizations.
78 int trampoline_pc_;
79};
80
81class SafepointTable {
82 public:
83 explicit SafepointTable(Code code);
84 explicit SafepointTable(Address instruction_start,
85 size_t safepoint_table_offset, uint32_t stack_slots,
86 bool has_deopt = false);
87
88 int size() const {
89 return kHeaderSize + (length_ * (kFixedEntrySize + entry_size_));
90 }
91 unsigned length() const { return length_; }
92 unsigned entry_size() const { return entry_size_; }
93
94 unsigned GetPcOffset(unsigned index) const {
95 DCHECK(index < length_);
96 return Memory<uint32_t>(GetPcOffsetLocation(index));
97 }
98
99 int GetTrampolinePcOffset(unsigned index) const {
100 DCHECK(index < length_);
101 return Memory<int>(GetTrampolineLocation(index));
102 }
103
104 unsigned find_return_pc(unsigned pc_offset);
105
106 SafepointEntry GetEntry(unsigned index) const {
107 DCHECK(index < length_);
108 unsigned info = Memory<uint32_t>(GetEncodedInfoLocation(index));
109 uint8_t* bits = &Memory<uint8_t>(entries_ + (index * entry_size_));
110 int trampoline_pc =
111 has_deopt_ ? Memory<int>(GetTrampolineLocation(index)) : -1;
112 return SafepointEntry(info, bits, trampoline_pc);
113 }
114
115 // Returns the entry for the given pc.
116 SafepointEntry FindEntry(Address pc) const;
117
118 void PrintEntry(unsigned index, std::ostream& os) const; // NOLINT
119
120 private:
121 static const uint8_t kNoRegisters = 0xFF;
122
123 // Layout information
124 static const int kLengthOffset = 0;
125 static const int kEntrySizeOffset = kLengthOffset + kIntSize;
126 static const int kHeaderSize = kEntrySizeOffset + kIntSize;
127 static const int kPcOffset = 0;
128 static const int kEncodedInfoOffset = kPcOffset + kIntSize;
129 static const int kTrampolinePcOffset = kEncodedInfoOffset + kIntSize;
130 static const int kFixedEntrySize = kTrampolinePcOffset + kIntSize;
131
132 Address GetPcOffsetLocation(unsigned index) const {
133 return pc_and_deoptimization_indexes_ + (index * kFixedEntrySize);
134 }
135
136 Address GetEncodedInfoLocation(unsigned index) const {
137 return GetPcOffsetLocation(index) + kEncodedInfoOffset;
138 }
139
140 Address GetTrampolineLocation(unsigned index) const {
141 return GetPcOffsetLocation(index) + kTrampolinePcOffset;
142 }
143
144 static void PrintBits(std::ostream& os, // NOLINT
145 uint8_t byte, int digits);
146
147 DISALLOW_HEAP_ALLOCATION(no_allocation_)
148 Address instruction_start_;
149 uint32_t stack_slots_;
150 unsigned length_;
151 unsigned entry_size_;
152
153 Address pc_and_deoptimization_indexes_;
154 Address entries_;
155 bool has_deopt_;
156
157 friend class SafepointTableBuilder;
158 friend class SafepointEntry;
159
160 DISALLOW_COPY_AND_ASSIGN(SafepointTable);
161};
162
163class Safepoint {
164 public:
165 typedef enum {
166 kSimple = 0,
167 kWithRegisters = 1 << 0,
168 kWithDoubles = 1 << 1,
169 kWithRegistersAndDoubles = kWithRegisters | kWithDoubles
170 } Kind;
171
172 enum DeoptMode {
173 kNoLazyDeopt,
174 kLazyDeopt
175 };
176
177 static const int kNoDeoptimizationIndex =
178 SafepointEntry::DeoptimizationIndexField::kMax;
179
180 void DefinePointerSlot(int index) { indexes_->push_back(index); }
181 void DefinePointerRegister(Register reg);
182
183 private:
184 Safepoint(ZoneChunkList<int>* indexes, ZoneChunkList<int>* registers)
185 : indexes_(indexes), registers_(registers) {}
186 ZoneChunkList<int>* const indexes_;
187 ZoneChunkList<int>* const registers_;
188
189 friend class SafepointTableBuilder;
190};
191
192class SafepointTableBuilder {
193 public:
194 explicit SafepointTableBuilder(Zone* zone)
195 : deoptimization_info_(zone),
196 emitted_(false),
197 last_lazy_safepoint_(0),
198 zone_(zone) {}
199
200 // Get the offset of the emitted safepoint table in the code.
201 unsigned GetCodeOffset() const;
202
203 // Define a new safepoint for the current position in the body.
204 Safepoint DefineSafepoint(Assembler* assembler,
205 Safepoint::Kind kind,
206 Safepoint::DeoptMode mode);
207
208 // Record deoptimization index for lazy deoptimization for the last
209 // outstanding safepoints.
210 void RecordLazyDeoptimizationIndex(int index);
211 void BumpLastLazySafepointIndex() {
212 last_lazy_safepoint_ = deoptimization_info_.size();
213 }
214
215 // Emit the safepoint table after the body. The number of bits per
216 // entry must be enough to hold all the pointer indexes.
217 V8_EXPORT_PRIVATE void Emit(Assembler* assembler, int bits_per_entry);
218
219 // Find the Deoptimization Info with pc offset {pc} and update its
220 // trampoline field. Calling this function ensures that the safepoint
221 // table contains the trampoline PC {trampoline} that replaced the
222 // return PC {pc} on the stack.
223 int UpdateDeoptimizationInfo(int pc, int trampoline, int start);
224
225 private:
226 struct DeoptimizationInfo {
227 unsigned pc;
228 unsigned deopt_index;
229 bool has_doubles;
230 int trampoline;
231 ZoneChunkList<int>* indexes;
232 ZoneChunkList<int>* registers;
233 DeoptimizationInfo(Zone* zone, unsigned pc, Safepoint::Kind kind)
234 : pc(pc),
235 deopt_index(Safepoint::kNoDeoptimizationIndex),
236 has_doubles(kind & Safepoint::kWithDoubles),
237 trampoline(-1),
238 indexes(new (zone) ZoneChunkList<int>(
239 zone, ZoneChunkList<int>::StartMode::kSmall)),
240 registers(kind & Safepoint::kWithRegisters
241 ? new (zone) ZoneChunkList<int>(
242 zone, ZoneChunkList<int>::StartMode::kSmall)
243 : nullptr) {}
244 };
245
246 // Encodes all fields of a {DeoptimizationInfo} except {pc} and {trampoline}.
247 uint32_t EncodeExceptPC(const DeoptimizationInfo&);
248
249 // Compares all fields of a {DeoptimizationInfo} except {pc} and {trampoline}.
250 bool IsIdenticalExceptForPc(const DeoptimizationInfo&,
251 const DeoptimizationInfo&) const;
252
253 // If all entries are identical, replace them by 1 entry with pc = kMaxUInt32.
254 void RemoveDuplicates();
255
256 ZoneChunkList<DeoptimizationInfo> deoptimization_info_;
257
258 unsigned offset_;
259 bool emitted_;
260 size_t last_lazy_safepoint_;
261
262 Zone* zone_;
263
264 DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
265};
266
267} // namespace internal
268} // namespace v8
269
270#endif // V8_SAFEPOINT_TABLE_H_
271