v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
safepoint-table.h
Go to the documentation of this file.
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_CODEGEN_SAFEPOINT_TABLE_H_
6#define V8_CODEGEN_SAFEPOINT_TABLE_H_
7
13#include "src/utils/utils.h"
15#include "src/zone/zone.h"
16
17namespace v8 {
18namespace internal {
19
20class GcSafeCode;
21
22namespace wasm {
23class WasmCode;
24} // namespace wasm
25
27 public:
28 SafepointEntry() = default;
29
37
38 bool operator==(const SafepointEntry& other) const {
39 return this->SafepointEntryBase::operator==(other) &&
40 tagged_register_indexes_ == other.tagged_register_indexes_ &&
41 tagged_slots_ == other.tagged_slots_;
42 }
43
44 uint32_t tagged_register_indexes() const {
47 }
48
54
55 private:
58};
59
60// A wrapper class for accessing the safepoint table embedded into the
61// InstructionStream object.
63 public:
64 // The isolate and pc arguments are used for figuring out whether pc
65 // belongs to the embedded or un-embedded code blob.
66 explicit SafepointTable(Isolate* isolate, Address pc,
68 explicit SafepointTable(Isolate* isolate, Address pc, Tagged<Code> code);
69#if V8_ENABLE_WEBASSEMBLY
70 explicit SafepointTable(const wasm::WasmCode* code);
71#endif // V8_ENABLE_WEBASSEMBLY
72
75
76 int stack_slots() const { return stack_slots_; }
77
78 int length() const { return length_; }
79
80 int byte_size() const {
81 return kHeaderSize + length_ * (entry_size() + tagged_slots_bytes());
82 }
83
85
86 SafepointEntry GetEntry(int index) const {
87 DCHECK_GT(length_, index);
88 Address entry_ptr =
89 safepoint_table_address_ + kHeaderSize + index * entry_size();
90
91 int pc = read_bytes(&entry_ptr, pc_size());
92 int deopt_index = SafepointEntry::kNoDeoptIndex;
93 int trampoline_pc = SafepointEntry::kNoTrampolinePC;
94 if (has_deopt_data()) {
95 static_assert(SafepointEntry::kNoDeoptIndex == -1);
96 static_assert(SafepointEntry::kNoTrampolinePC == -1);
97 // `-1` to restore the original value, see also
98 // SafepointTableBuilder::Emit.
99 deopt_index = read_bytes(&entry_ptr, deopt_index_size()) - 1;
100 trampoline_pc = read_bytes(&entry_ptr, pc_size()) - 1;
101 DCHECK(deopt_index >= 0 || deopt_index == SafepointEntry::kNoDeoptIndex);
102 DCHECK(trampoline_pc >= 0 ||
103 trampoline_pc == SafepointEntry::kNoTrampolinePC);
104 }
105 int tagged_register_indexes =
106 read_bytes(&entry_ptr, register_indexes_size());
107
108 // Entry bits start after the the vector of entries (thus the pc offset of
109 // the non-existing entry after the last one).
110 uint8_t* tagged_slots_start = reinterpret_cast<uint8_t*>(
111 safepoint_table_address_ + kHeaderSize + length_ * entry_size());
113 tagged_slots_start + index * tagged_slots_bytes(),
115
116 return SafepointEntry(pc, deopt_index, tagged_register_indexes,
117 tagged_slots, trampoline_pc);
118 }
119
120 // Returns the entry for the given pc.
123 Address pc);
124 // Tries to find the entry for the given pc. If the entry does not exist, it
125 // returns an uninitialized entry.
127
128 void Print(std::ostream&) const;
129
130 private:
132
133 // Layout information.
134#define FIELD_LIST(V) \
135 V(kStackSlotsOffset, sizeof(SafepointTableStackSlotsField_t)) \
136 V(kLengthOffset, kIntSize) \
137 V(kEntryConfigurationOffset, kUInt32Size) \
138 V(kHeaderSize, 0)
139
141#undef FIELD_LIST
142
143 static_assert(kStackSlotsOffset == kSafepointTableStackSlotsOffset);
144
149 // In 22 bits, we can encode up to 4M bytes, corresponding to 32M frame slots,
150 // which is 128MB on 32-bit and 256MB on 64-bit systems. The stack size is
151 // limited to a bit below 1MB anyway (see v8_flags.stack_size).
153
154 SafepointTable(Address instruction_start, Address safepoint_table_address);
155
156 int entry_size() const {
157 int deopt_data_size = has_deopt_data() ? pc_size() + deopt_index_size() : 0;
158 return pc_size() + deopt_data_size + register_indexes_size();
159 }
160
174
175 static int read_bytes(Address* ptr, int bytes) {
176 uint32_t result = 0;
177 for (int b = 0; b < bytes; ++b, ++*ptr) {
178 result |= uint32_t{*reinterpret_cast<uint8_t*>(*ptr)} << (8 * b);
179 }
180 return static_cast<int>(result);
181 }
182
184
186
187 // Safepoint table layout.
190 const int length_;
191 const uint32_t entry_configuration_;
192
194 friend class SafepointEntry;
195};
196
198 private:
200 int pc;
201 int deopt_index = SafepointEntry::kNoDeoptIndex;
202 int trampoline = SafepointEntry::kNoTrampolinePC;
204 uint32_t register_indexes = 0;
205 EntryBuilder(Zone* zone, int pc)
206 : pc(pc), stack_indexes(zone->New<GrowableBitVector>()) {}
207 };
208
209 public:
210 explicit SafepointTableBuilder(Zone* zone) : entries_(zone), zone_(zone) {}
211
214
215 class Safepoint {
216 public:
217 void DefineTaggedStackSlot(int index) {
218 // Note it is only valid to specify stack slots here that are *not* in
219 // the fixed part of the frame (e.g. argc, target, context, stored rbp,
220 // return address). Frame iteration handles the fixed part of the frame
221 // with custom code, see Turbofan::Iterate.
222 entry_->stack_indexes->Add(index, table_->zone_);
223 table_->UpdateMinMaxStackIndex(index);
224 }
225
226 void DefineTaggedRegister(int reg_code) {
227 DCHECK_LT(reg_code,
228 kBitsPerByte * sizeof(EntryBuilder::register_indexes));
229 entry_->register_indexes |= 1u << reg_code;
230 }
231
232 private:
235 : entry_(entry), table_(table) {}
238 };
239
240 // Define a new safepoint for the current position in the body. The
241 // `pc_offset` parameter allows to define a different offset than the current
242 // pc_offset.
243 Safepoint DefineSafepoint(Assembler* assembler, int pc_offset = 0);
244
245 // Emit the safepoint table after the body.
246 V8_EXPORT_PRIVATE void Emit(Assembler* assembler, int stack_slot_count);
247
248 // Find the Deoptimization Info with pc offset {pc} and update its
249 // trampoline field. Calling this function ensures that the safepoint
250 // table contains the trampoline PC {trampoline} that replaced the
251 // return PC {pc} on the stack.
252 int UpdateDeoptimizationInfo(int pc, int trampoline, int start,
253 int deopt_index);
254
255 private:
256 // Remove consecutive identical entries.
257 void RemoveDuplicates();
258
259 void UpdateMinMaxStackIndex(int index) {
260#ifdef DEBUG
261 if (index > max_stack_index_) max_stack_index_ = index;
262#endif // DEBUG
263 if (index < min_stack_index_) min_stack_index_ = index;
264 }
265
266 int min_stack_index() const {
267 return min_stack_index_ == std::numeric_limits<int>::max()
268 ? 0
269 : min_stack_index_;
270 }
271
272 // Tracks the min/max stack slot index over all entries. We need the minimum
273 // index when encoding the actual table since we shift all unused lower
274 // indices out of the encoding. Tracking the indices during safepoint
275 // construction means we don't have to iterate again later.
276#ifdef DEBUG
277 int max_stack_index_ = 0;
278#endif // DEBUG
279 int min_stack_index_ = std::numeric_limits<int>::max();
280
283};
284
285} // namespace internal
286} // namespace v8
287
288#endif // V8_CODEGEN_SAFEPOINT_TABLE_H_
#define DISALLOW_GARBAGE_COLLECTION(name)
static constexpr T decode(U value)
Definition bit-field.h:66
constexpr T * data() const
Definition vector.h:100
bool operator==(const SafepointEntryBase &other) const
bool operator==(const SafepointEntry &other) const
SafepointEntry(int pc, int deopt_index, uint32_t tagged_register_indexes, base::Vector< uint8_t > tagged_slots, int trampoline_pc)
base::Vector< uint8_t > tagged_slots_
base::Vector< const uint8_t > tagged_slots() const
uint32_t tagged_register_indexes() const
Safepoint(EntryBuilder *entry, SafepointTableBuilder *table)
SafepointTableBuilder(const SafepointTableBuilder &)=delete
SafepointTableBuilder & operator=(const SafepointTableBuilder &)=delete
ZoneDeque< EntryBuilder > entries_
void Print(std::ostream &) const
SafepointEntry TryFindEntry(Address pc) const
SafepointTable & operator=(const SafepointTable &)=delete
SafepointTable(const SafepointTable &)=delete
const SafepointTableStackSlotsField_t stack_slots_
static int read_bytes(Address *ptr, int bytes)
SafepointEntry FindEntry(Address pc) const
int find_return_pc(int pc_offset)
SafepointTable(Isolate *isolate, Address pc, Tagged< InstructionStream > code)
SafepointEntry GetEntry(int index) const
Zone * zone_
int start
DisallowGarbageCollection no_gc_
HeapEntry * entry_
ZoneVector< RpoNumber > & result
std::vector< EntryBuilder > entries_
int pc_offset
#define FIELD_LIST(V)
constexpr int kBitsPerByte
Definition globals.h:682
uint32_t SafepointTableStackSlotsField_t
constexpr int kSafepointTableStackSlotsOffset
Definition c-api.cc:87
SourcePositionTable *const table_
Definition pipeline.cc:227
ro::BitSet tagged_slots
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define DEFINE_FIELD_OFFSET_CONSTANTS(StartOffset, LIST_MACRO)
Definition utils.h:242