v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
code-pointer-table-inl.h
Go to the documentation of this file.
1// Copyright 2023 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_CODE_POINTER_TABLE_INL_H_
6#define V8_SANDBOX_CODE_POINTER_TABLE_INL_H_
7
9// Include the non-inl header before the rest of the headers.
10
13
14#ifdef V8_COMPRESS_POINTERS
15
16namespace v8 {
17namespace internal {
18
19void CodePointerTableEntry::MakeCodePointerEntry(Address code,
20 Address entrypoint,
22 bool mark_as_alive) {
23 DCHECK_EQ(code & kMarkingBit, 0);
24 DCHECK_EQ(entrypoint >> kCodeEntrypointTagShift, 0);
26
27 if (mark_as_alive) code |= kMarkingBit;
28 entrypoint_.store(entrypoint ^ tag, std::memory_order_relaxed);
29 code_.store(code, std::memory_order_relaxed);
30}
31
32Address CodePointerTableEntry::GetEntrypoint(CodeEntrypointTag tag) const {
33 DCHECK(!IsFreelistEntry());
34 return entrypoint_.load(std::memory_order_relaxed) ^ tag;
35}
36
37void CodePointerTableEntry::SetEntrypoint(Address value,
39 DCHECK(!IsFreelistEntry());
42
43 entrypoint_.store(value ^ tag, std::memory_order_relaxed);
44}
45
46Address CodePointerTableEntry::GetCodeObject() const {
47 DCHECK(!IsFreelistEntry());
48 // We reuse the heap object tag bit as marking bit, so we need to explicitly
49 // set it here when accessing the pointer.
50 return code_.load(std::memory_order_relaxed) | kMarkingBit;
51}
52
53void CodePointerTableEntry::SetCodeObject(Address new_value) {
54 DCHECK(!IsFreelistEntry());
55 // SetContent shouldn't change the marking state of the entry. Currently this
56 // is always automatically the case, but if this ever fails, we might need to
57 // manually copy the marking bit.
58 DCHECK_EQ(code_ & kMarkingBit, new_value & kMarkingBit);
59 code_.store(new_value, std::memory_order_relaxed);
60}
61
62void CodePointerTableEntry::MakeFreelistEntry(uint32_t next_entry_index) {
63 Address value = kFreeEntryTag | next_entry_index;
64 entrypoint_.store(value, std::memory_order_relaxed);
65 code_.store(kNullAddress, std::memory_order_relaxed);
66}
67
68bool CodePointerTableEntry::IsFreelistEntry() const {
69 auto entrypoint = entrypoint_.load(std::memory_order_relaxed);
70 return (entrypoint & kFreeEntryTag) == kFreeEntryTag;
71}
72
73uint32_t CodePointerTableEntry::GetNextFreelistEntryIndex() const {
74 return static_cast<uint32_t>(entrypoint_.load(std::memory_order_relaxed));
75}
76
77void CodePointerTableEntry::Mark() {
78 Address old_value = code_.load(std::memory_order_relaxed);
79 Address new_value = old_value | kMarkingBit;
80
81 // We don't need to perform the CAS in a loop since it can only fail if a new
82 // value has been written into the entry. This, however, will also have set
83 // the marking bit.
84 bool success = code_.compare_exchange_strong(old_value, new_value,
85 std::memory_order_relaxed);
86 DCHECK(success || (old_value & kMarkingBit) == kMarkingBit);
87 USE(success);
88}
89
90void CodePointerTableEntry::Unmark() {
91 Address value = code_.load(std::memory_order_relaxed);
92 value &= ~kMarkingBit;
93 code_.store(value, std::memory_order_relaxed);
94}
95
96bool CodePointerTableEntry::IsMarked() const {
97 Address value = code_.load(std::memory_order_relaxed);
98 return value & kMarkingBit;
99}
100
101Address CodePointerTable::GetEntrypoint(CodePointerHandle handle,
102 CodeEntrypointTag tag) const {
103 uint32_t index = HandleToIndex(handle);
104 return at(index).GetEntrypoint(tag);
105}
106
107Address CodePointerTable::GetCodeObject(CodePointerHandle handle) const {
108 uint32_t index = HandleToIndex(handle);
109 // Due to the fact that we use the heap object tag as marking bit, this table
110 // (in contrast to the trusted pointer table) does not return Smi::zero() for
111 // the 0th entry. That entry must therefore not be accessed here.
112 DCHECK_NE(index, 0);
113 return at(index).GetCodeObject();
114}
115
116void CodePointerTable::SetEntrypoint(CodePointerHandle handle, Address value,
117 CodeEntrypointTag tag) {
119 uint32_t index = HandleToIndex(handle);
120 CFIMetadataWriteScope write_scope("CodePointerTable write");
121 at(index).SetEntrypoint(value, tag);
122}
123
124void CodePointerTable::SetCodeObject(CodePointerHandle handle, Address value) {
126 uint32_t index = HandleToIndex(handle);
127 CFIMetadataWriteScope write_scope("CodePointerTable write");
128 at(index).SetCodeObject(value);
129}
130
131CodePointerHandle CodePointerTable::AllocateAndInitializeEntry(
132 Space* space, Address code, Address entrypoint, CodeEntrypointTag tag) {
133 DCHECK(space->BelongsTo(this));
134 uint32_t index = AllocateEntry(space);
135 CFIMetadataWriteScope write_scope("CodePointerTable write");
136 at(index).MakeCodePointerEntry(code, entrypoint, tag,
137 space->allocate_black());
138 return IndexToHandle(index);
139}
140
141void CodePointerTable::Mark(Space* space, CodePointerHandle handle) {
142 DCHECK(space->BelongsTo(this));
143 // The null entry is immortal and immutable, so no need to mark it as alive.
144 if (handle == kNullCodePointerHandle) return;
145
146 uint32_t index = HandleToIndex(handle);
147 DCHECK(space->Contains(index));
148
149 CFIMetadataWriteScope write_scope("CodePointerTable write");
150 at(index).Mark();
151}
152
153template <typename Callback>
154void CodePointerTable::IterateActiveEntriesIn(Space* space, Callback callback) {
155 IterateEntriesIn(space, [&](uint32_t index) {
156 if (!at(index).IsFreelistEntry()) {
157 callback(IndexToHandle(index), at(index).GetCodeObject());
158 }
159 });
160}
161
162uint32_t CodePointerTable::HandleToIndex(CodePointerHandle handle) const {
163 uint32_t index = handle >> kCodePointerHandleShift;
166 return index;
167}
168
169CodePointerHandle CodePointerTable::IndexToHandle(uint32_t index) const {
173}
174
175} // namespace internal
176} // namespace v8
177
178#endif // V8_COMPRESS_POINTERS
179
180#endif // V8_SANDBOX_CODE_POINTER_TABLE_INL_H_
ZoneList< RegExpInstruction > code_
TNode< Object > callback
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
IndirectPointerHandle CodePointerHandle
constexpr uint32_t kCodePointerHandleShift
constexpr CodePointerHandle kNullCodePointerHandle
static constexpr Address kNullAddress
Definition v8-internal.h:53
constexpr uint32_t kCodePointerHandleMarker
RwxMemoryWriteScope CFIMetadataWriteScope
constexpr int kCodeEntrypointTagShift
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293