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