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