v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
segmented-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_COMMON_SEGMENTED_TABLE_H_
6#define V8_COMMON_SEGMENTED_TABLE_H_
7
9#include "src/base/macros.h"
11
12namespace v8 {
13namespace internal {
14
33template <typename Entry, size_t size>
35 protected:
36 static constexpr bool kIsWriteProtected = Entry::IsWriteProtected;
37 static constexpr int kEntrySize = sizeof(Entry);
38
39#ifdef V8_TARGET_ARCH_64_BIT
40 // On 64 bit, we use a large address space reservation for the table memory.
41 static constexpr bool kUseContiguousMemory = true;
42 static constexpr size_t kReservationSize = size;
43 static constexpr size_t kMaxCapacity = kReservationSize / kEntrySize;
44#else
45 // On 32 bit, segments are individually mapped.
46 static constexpr bool kUseContiguousMemory = false;
47#endif
48
49 // The sandbox relies on not being able to access any SegmentedTable out of
50 // bounds.
51 static_assert(kUseContiguousMemory || !V8_ENABLE_SANDBOX_BOOL);
52
53 // For managing the table's backing memory, the table is partitioned into
54 // segments of this size. Segments can then be allocated and freed using the
55 // AllocateAndInitializeSegment() and FreeTableSegment() routines.
56 static constexpr size_t kSegmentSize = 64 * KB;
57 static constexpr size_t kEntriesPerSegment = kSegmentSize / kEntrySize;
58
59 // Struct representing a segment of the table.
60 struct Segment {
61 public:
62 // Initialize a segment given its number.
63 explicit Segment(uint32_t number) : number_(number) {}
64
65 // Returns the segment starting at the specified offset from the base of the
66 // table.
67 static Segment At(uint32_t offset);
68
69 // Returns the segment containing the entry at the given index.
70 static Segment Containing(uint32_t entry_index);
71
72 // The segments of a table are numbered sequentially. This method returns
73 // the number of this segment.
74 uint32_t number() const { return number_; }
75
76 // Returns the offset of this segment from the table base.
77 uint32_t offset() const { return number_ * kSegmentSize; }
78
79 // Returns the index of the first entry in this segment.
80 uint32_t first_entry() const { return number_ * kEntriesPerSegment; }
81
82 // Return the index of the last entry in this segment.
83 uint32_t last_entry() const {
84 return first_entry() + kEntriesPerSegment - 1;
85 }
86
87 // Segments are ordered by their id/offset.
88 bool operator<(const Segment& other) const {
89 return number_ < other.number_;
90 }
91
92 private:
93 // A segment is identified by its number, which is its offset from the base
94 // of the table divided by the segment size.
95 const uint32_t number_;
96 };
97
98 // Struct representing the head of the freelist.
99 //
100 // A segmented table uses simple, singly-linked lists to manage free entries.
101 // Each entry on the freelist contains the 32-bit index of the next entry. The
102 // last entry points to zero.
104 constexpr FreelistHead() : next_(0), length_(0) {}
105 constexpr FreelistHead(uint32_t next, uint32_t length)
106 : next_(next), length_(length) {}
107
108 // Returns the index of the next entry on the freelist.
109 // If the freelist is empty, this returns zero.
110 uint32_t next() const { return next_; }
111
112 // Returns the total length of the freelist.
113 uint32_t length() const { return length_; }
114
115 bool is_empty() const { return length_ == 0; }
116
117 private:
118 uint32_t next_;
119 uint32_t length_;
120 };
121
122 // We expect the FreelistHead struct to fit into a single atomic word.
123 // Otherwise, access to it would be slow.
124 static_assert(std::atomic<FreelistHead>::is_always_lock_free);
125
126 SegmentedTable() = default;
129
130 // This Iterator also acts as a scope object to temporarily lift any
131 // write-protection (if kIsWriteProtected is true).
133 public:
134 explicit WriteIterator(Entry* base, uint32_t index);
135
136 uint32_t index() const { return index_; }
137 Entry* operator->() {
138 DCHECK(!crossed_segment_);
139 return &base_[index_];
140 }
141 Entry& operator*() {
142 DCHECK(!crossed_segment_);
143 return base_[index_];
144 }
146 index_++;
147#ifdef DEBUG
148 if (IsAligned(index_, kEntriesPerSegment)) {
149 crossed_segment_ = true;
150 }
151#endif
152 return *this;
153 }
155 DCHECK_GT(index_, 0);
156#ifdef DEBUG
157 if (IsAligned(index_, kEntriesPerSegment)) {
158 crossed_segment_ = true;
159 }
160#endif
161 index_--;
162 return *this;
163 }
164
165 private:
166 Entry* base_;
167 uint32_t index_;
168 std::conditional_t<kIsWriteProtected, CFIMetadataWriteScope,
171#ifdef DEBUG
172 bool crossed_segment_ = false;
173#endif
174 };
175
176 // Access the entry at the specified index.
177 Entry& at(uint32_t index);
178 const Entry& at(uint32_t index) const;
179
180 // Returns an iterator that can be used to perform multiple write operations
181 // without switching the write-protections all the time (if kIsWriteProtected
182 // is true).
183 WriteIterator iter_at(uint32_t index);
184
185 // Returns true if this table has been initialized.
186 bool is_initialized() const;
187
188 // Returns the base address of this table.
189 Address base() const;
190
191 // Allocate a new segment in this table.
192 //
193 // The segment is initialized with freelist entries.
194 std::pair<Segment, FreelistHead> AllocateAndInitializeSegment();
195 // Same as above but fails if there is no space left.
196 std::optional<std::pair<Segment, FreelistHead>>
197 TryAllocateAndInitializeSegment();
198
199 // Initialize a table segment with a freelist.
200 //
201 // Note that you don't need to call this function on segments allocated with
202 // `AllocateAndInitializeSegment()` since those already get initialized.
203 FreelistHead InitializeFreeList(Segment segment, uint32_t start_offset = 0);
204
205 // Free the specified segment of this table.
206 //
207 // The memory of this segment will afterwards be inaccessible.
208 void FreeTableSegment(Segment segment);
209
210 // Initializes the table by reserving the backing memory, allocating an
211 // initial segment, and populating the freelist.
212 void Initialize();
213
214 // Deallocates all memory associated with this table.
215 void TearDown();
216
217 // The pointer to the base of the virtual address space backing this table.
218 // All entry accesses happen through this pointer.
219 // It is equivalent to |vas_->base()| and is effectively const after
220 // initialization since the backing memory is never reallocated.
221 Entry* base_ = nullptr;
222
223 // The virtual address space backing this table.
224 // This is used to manage the underlying OS pages, in particular to allocate
225 // and free the segments that make up the table.
226 VirtualAddressSpace* vas_ = nullptr;
227};
228
229} // namespace internal
230} // namespace v8
231
232#endif // V8_COMMON_SEGMENTED_TABLE_H_
std::conditional_t< kIsWriteProtected, CFIMetadataWriteScope, NopRwxMemoryWriteScope > write_scope_
SegmentedTable(const SegmentedTable &)=delete
SegmentedTable & operator=(const SegmentedTable &)=delete
Register const index_
#define V8_ENABLE_SANDBOX_BOOL
Definition globals.h:160
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation trace turbo cfg trace TurboFan s graph trimmer trace TurboFan s control equivalence trace TurboFan s register allocator trace stack load store counters for optimized code in run fuzzing &&concurrent_recompilation trace_turbo trace_turbo_scheduled trace_turbo_stack_accesses verify TurboFan machine graph of code stubs enable FixedArray bounds checks print TurboFan statistics of wasm compilations maximum cumulative size of bytecode considered for inlining scale factor of bytecode size used to calculate the inlining budget * KB
int32_t offset
const int length_
Definition mul-fft.cc:473
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460
constexpr bool IsAligned(T value, U alignment)
Definition macros.h:403
constexpr FreelistHead(uint32_t next, uint32_t length)
bool operator<(const Segment &other) const