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/utils.h"
11 : #include "src/v8memory.h"
12 : #include "src/zone/zone-chunk-list.h"
13 : #include "src/zone/zone.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : class Register;
19 :
20 : class SafepointEntry {
21 : public:
22 64965082 : SafepointEntry() : info_(0), bits_(nullptr), trampoline_pc_(-1) {}
23 :
24 : SafepointEntry(unsigned info, uint8_t* bits, int trampoline_pc)
25 2864350 : : 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 912862 : info_ = 0;
37 912862 : 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 :
81 : class 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 37551947 : return Memory<uint32_t>(GetPcOffsetLocation(index));
97 : }
98 :
99 : int GetTrampolinePcOffset(unsigned index) const {
100 : DCHECK(index < length_);
101 34674526 : 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 2864350 : unsigned info = Memory<uint32_t>(GetEncodedInfoLocation(index));
109 2864350 : uint8_t* bits = &Memory<uint8_t>(entries_ + (index * entry_size_));
110 : int trampoline_pc =
111 5716039 : 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 37525727 : return pc_and_deoptimization_indexes_ + (index * kFixedEntrySize);
134 : }
135 :
136 : Address GetEncodedInfoLocation(unsigned index) const {
137 2864350 : return GetPcOffsetLocation(index) + kEncodedInfoOffset;
138 : }
139 :
140 : Address GetTrampolineLocation(unsigned index) const {
141 37526215 : 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 :
163 : class 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 15827297 : 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 :
192 : class SafepointTableBuilder {
193 : public:
194 : explicit SafepointTableBuilder(Zone* zone)
195 : : deoptimization_info_(zone),
196 : emitted_(false),
197 : last_lazy_safepoint_(0),
198 3103296 : 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 6450145 : DeoptimizationInfo(Zone* zone, unsigned pc, Safepoint::Kind kind)
234 : : pc(pc),
235 : deopt_index(Safepoint::kNoDeoptimizationIndex),
236 6450145 : has_doubles(kind & Safepoint::kWithDoubles),
237 : trampoline(-1),
238 : indexes(new (zone) ZoneChunkList<int>(
239 : zone, ZoneChunkList<int>::StartMode::kSmall)),
240 6450190 : registers(kind & Safepoint::kWithRegisters
241 : ? new (zone) ZoneChunkList<int>(
242 : zone, ZoneChunkList<int>::StartMode::kSmall)
243 32250860 : : 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_
|