v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
cppheap-pointer-table.h
Go to the documentation of this file.
1// Copyright 2024 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_SANDBOX_CPPHEAP_POINTER_TABLE_H_
6#define V8_SANDBOX_CPPHEAP_POINTER_TABLE_H_
7
9#include "include/v8config.h"
10#include "src/base/atomicops.h"
11#include "src/base/bounds.h"
12#include "src/base/memory.h"
13#include "src/common/globals.h"
17
18#ifdef V8_COMPRESS_POINTERS
19
20namespace v8 {
21namespace internal {
22
23class Isolate;
24class Counters;
25
39struct CppHeapPointerTableEntry {
40 // Make this entry a cpp heap pointer entry containing the given pointer
41 // tagged with the given tag.
42 inline void MakePointerEntry(Address value, CppHeapPointerTag tag,
43 bool mark_as_alive);
44
45 // Load and untag the pointer stored in this entry.
46 // This entry must be a pointer entry.
47 // If the tag of the entry is not within the specified tag range, the
48 // resulting pointer will be invalid and cannot be dereferenced.
49 inline Address GetPointer(CppHeapPointerTagRange tag_range) const;
50
51 // Tag and store the given pointer in this entry.
52 // This entry must be a pointer entry.
53 inline void SetPointer(Address value, CppHeapPointerTag tag);
54
55 // Returns true if this entry contains a pointer whose tag is within the
56 // specified tag range.
57 inline bool HasPointer(CppHeapPointerTagRange tag_range) const;
58
59 // Invalidate the entry. Any access to a zapped entry will result in an
60 // invalid pointer that will crash upon dereference.
61 inline void MakeZappedEntry();
62
63 // Make this entry a freelist entry, containing the index of the next entry
64 // on the freelist.
65 inline void MakeFreelistEntry(uint32_t next_entry_index);
66
67 // Get the index of the next entry on the freelist. This method may be
68 // called even when the entry is not a freelist entry. However, the result
69 // is only valid if this is a freelist entry. This behaviour is required
70 // for efficient entry allocation, see TryAllocateEntryFromFreelist.
71 inline uint32_t GetNextFreelistEntryIndex() const;
72
73 // Make this entry an evacuation entry containing the address of the handle to
74 // the entry being evacuated.
75 inline void MakeEvacuationEntry(Address handle_location);
76
77 // Returns true if this entry contains an evacuation entry.
78 inline bool HasEvacuationEntry() const;
79
80 // Move the content of this entry into the provided entry, possibly clearing
81 // the marking bit. Used during table compaction and during promotion.
82 // Invalidates the source entry.
83 inline void Evacuate(CppHeapPointerTableEntry& dest);
84
85 // Mark this entry as alive during table garbage collection.
86 inline void Mark();
87
88 static constexpr bool IsWriteProtected = false;
89
90 private:
91 friend class CppHeapPointerTable;
92
93 struct Payload {
94 Payload(Address pointer, CppHeapPointerTag tag)
95 : encoded_word_(Tag(pointer, tag)) {}
96
97 Address Untag(CppHeapPointerTagRange tag_range) const {
98 Address content = encoded_word_;
99 if (V8_LIKELY(tag_range.CheckTagOf(content))) {
100 content >>= kCppHeapPointerPayloadShift;
101 } else {
102 // If the type check failed, we simply return nullptr here. That way:
103 // 1. The null handle always results in nullptr being returned here,
104 // which is a desired property. Otherwise, we may need an explicit
105 // check for the null handle in the caller, and therefore an
106 // additional branch. This works because the 0th entry of the table
107 // always contains nullptr tagged with the null tag (i.e. an
108 // all-zeros entry). As such, regardless of whether the type check
109 // succeeds, the result will always be nullptr.
110 // 2. The returned pointer is guaranteed to crash even on platforms
111 // with top byte ignore (TBI), such as Arm64. The alternative would
112 // be to simply return the original entry with the left-shifted
113 // payload. However, due to TBI, an access to that may not always
114 // result in a crash (specifically, if the second most significant
115 // byte happens to be zero). In addition, there shouldn't be a
116 // difference on Arm64 between returning nullptr or the original
117 // entry, since it will simply compile to a `csel x0, x8, xzr, lo`
118 // instead of a `csel x0, x10, x8, lo` instruction.
119 content = 0;
120 }
121 return content;
122 }
123
124 Address Untag(CppHeapPointerTag tag) const {
125 return Untag(CppHeapPointerTagRange(tag, tag));
126 }
127
128 static Address Tag(Address pointer, CppHeapPointerTag tag) {
129 return (pointer << kCppHeapPointerPayloadShift) |
130 (static_cast<uint16_t>(tag) << kCppHeapPointerTagShift);
131 }
132
133 bool IsTaggedWithTagIn(CppHeapPointerTagRange tag_range) const {
134 return tag_range.CheckTagOf(encoded_word_);
135 }
136
137 bool IsTaggedWith(CppHeapPointerTag tag) const {
138 return IsTaggedWithTagIn(CppHeapPointerTagRange(tag, tag));
139 }
140
141 void SetMarkBit() { encoded_word_ |= kCppHeapPointerMarkBit; }
142
143 void ClearMarkBit() { encoded_word_ &= ~kCppHeapPointerMarkBit; }
144
145 bool HasMarkBitSet() const {
146 return encoded_word_ & kCppHeapPointerMarkBit;
147 }
148
149 uint32_t ExtractFreelistLink() const {
150 return static_cast<uint32_t>(encoded_word_ >>
152 }
153
154 CppHeapPointerTag ExtractTag() const { UNREACHABLE(); }
155
156 bool ContainsFreelistLink() const {
157 return IsTaggedWith(CppHeapPointerTag::kFreeEntryTag);
158 }
159
160 bool ContainsEvacuationEntry() const {
161 return IsTaggedWith(CppHeapPointerTag::kEvacuationEntryTag);
162 }
163
164 Address ExtractEvacuationEntryHandleLocation() const {
165 return Untag(CppHeapPointerTag::kEvacuationEntryTag);
166 }
167
168 bool ContainsPointer() const {
169 return !ContainsFreelistLink() && !ContainsEvacuationEntry();
170 }
171
172 bool operator==(Payload other) const {
173 return encoded_word_ == other.encoded_word_;
174 }
175
176 bool operator!=(Payload other) const {
177 return encoded_word_ != other.encoded_word_;
178 }
179
180 private:
181 Address encoded_word_;
182 };
183
184 inline Payload GetRawPayload() {
185 return payload_.load(std::memory_order_relaxed);
186 }
187 inline void SetRawPayload(Payload new_payload) {
188 return payload_.store(new_payload, std::memory_order_relaxed);
189 }
190
191 // CppHeapPointerTable entries consist of a single pointer-sized word
192 // containing a tag and marking bit together with the actual content.
193 std::atomic<Payload> payload_;
194};
195
196// We expect CppHeapPointerTable entries to consist of a single 64-bit word.
197static_assert(sizeof(CppHeapPointerTableEntry) == 8);
198
212class V8_EXPORT_PRIVATE CppHeapPointerTable
213 : public CompactibleExternalEntityTable<
214 CppHeapPointerTableEntry, kCppHeapPointerTableReservationSize> {
215 using Base =
216 CompactibleExternalEntityTable<CppHeapPointerTableEntry,
217 kCppHeapPointerTableReservationSize>;
218 static_assert(kMaxCppHeapPointers == kMaxCapacity);
219
220 public:
221 CppHeapPointerTable() = default;
222 CppHeapPointerTable(const CppHeapPointerTable&) = delete;
223 CppHeapPointerTable& operator=(const CppHeapPointerTable&) = delete;
224
225 // The Spaces used by an CppHeapPointerTable.
226 class Space : public Base::Space {
227 public:
228 bool allocate_black() { return allocate_black_; }
229 void set_allocate_black(bool allocate_black) {
230 allocate_black_ = allocate_black;
231 }
232
233 private:
234 bool allocate_black_ = false;
235 };
236
237 // Retrieves the entry referenced by the given handle.
238 //
239 // The tag of the entry must be within the specified range of tags.
240 //
241 // This method is atomic and can be called from background threads.
242 inline Address Get(CppHeapPointerHandle handle,
243 CppHeapPointerTagRange tag_range) const;
244
245 // Sets the entry referenced by the given handle.
246 //
247 // This method is atomic and can be called from background threads.
248 inline void Set(CppHeapPointerHandle handle, Address value,
249 CppHeapPointerTag tag);
250
251 // Allocates a new entry in the given space. The caller must provide the
252 // initial value and tag for the entry.
253 //
254 // This method is atomic and can be called from background threads.
255 inline CppHeapPointerHandle AllocateAndInitializeEntry(Space* space,
256 Address initial_value,
257 CppHeapPointerTag tag);
258
259 // Marks the specified entry as alive.
260 //
261 // If the space to which the entry belongs is currently being compacted, this
262 // may also mark the entry for evacuation for which the location of the
263 // handle is required. See the comments about the compaction algorithm for
264 // more details.
265 //
266 // This method is atomic and can be called from background threads.
267 inline void Mark(Space* space, CppHeapPointerHandle handle,
268 Address handle_location);
269
270 uint32_t SweepAndCompact(Space* space, Counters* counters);
271
272 inline bool Contains(Space* space, CppHeapPointerHandle handle) const;
273
274 private:
275 static inline bool IsValidHandle(CppHeapPointerHandle handle);
276 static inline uint32_t HandleToIndex(CppHeapPointerHandle handle);
277 static inline CppHeapPointerHandle IndexToHandle(uint32_t index);
278
279 void ResolveEvacuationEntryDuringSweeping(
280 uint32_t index, CppHeapPointerHandle* handle_location,
281 uint32_t start_of_evacuation_area);
282};
283
284} // namespace internal
285} // namespace v8
286
287#endif // V8_COMPRESS_POINTERS
288
289#endif // V8_SANDBOX_CPPHEAP_POINTER_TABLE_H_
unsigned short uint16_t
Definition unicode.cc:39
uintptr_t Address
Definition memory.h:13
bool operator==(PointerWithPayload< PointerType, PayloadType, NumPayloadBits > lhs, PointerWithPayload< PointerType, PayloadType, NumPayloadBits > rhs)
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Definition graph.h:1231
constexpr uint64_t kCppHeapPointerMarkBit
bool operator!=(ExternalReference lhs, ExternalReference rhs)
constexpr size_t kMaxCppHeapPointers
constexpr uint64_t kCppHeapPointerPayloadShift
constexpr uint64_t kCppHeapPointerTagShift
uint32_t CppHeapPointerHandle
CppHeapPointerTag
Definition v8-sandbox.h:28
#define UNREACHABLE()
Definition logging.h:67
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_LIKELY(condition)
Definition v8config.h:661