/src/hermes/include/hermes/VM/MarkBitArrayNC.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) Meta Platforms, Inc. and affiliates. |
3 | | * |
4 | | * This source code is licensed under the MIT license found in the |
5 | | * LICENSE file in the root directory of this source tree. |
6 | | */ |
7 | | |
8 | | #ifndef HERMES_VM_MARKBITARRAYNC_H |
9 | | #define HERMES_VM_MARKBITARRAYNC_H |
10 | | |
11 | | #include "hermes/ADT/BitArray.h" |
12 | | #include "hermes/Support/OSCompat.h" |
13 | | #include "hermes/VM/AlignedStorage.h" |
14 | | #include "hermes/VM/ExpectedPageSize.h" |
15 | | #include "hermes/VM/HeapAlign.h" |
16 | | |
17 | | namespace hermes { |
18 | | namespace vm { |
19 | | |
20 | | /// Encapsulates the array of bits used for marking the allocation region of an |
21 | | /// AlignedHeapSegment. The array expects to be constructed inside an |
22 | | /// AlignedHeapSegment's storage, at some position before the allocation region. |
23 | | class MarkBitArrayNC { |
24 | | public: |
25 | 226 | MarkBitArrayNC() = default; |
26 | | |
27 | | /// MarkBitArrayNC is not copyable or movable: It must be constructed |
28 | | /// in-place. |
29 | | MarkBitArrayNC(const MarkBitArrayNC &) = delete; |
30 | | MarkBitArrayNC(MarkBitArrayNC &&) = delete; |
31 | | MarkBitArrayNC &operator=(const MarkBitArrayNC &) = delete; |
32 | | MarkBitArrayNC &operator=(MarkBitArrayNC &&) = delete; |
33 | | |
34 | | /// Returns the size of the bit array, counted as a number of bits. |
35 | | /// |
36 | | /// For the sake of simplicity, there are enough bits to cover an allocation |
37 | | /// region that takes up all the space in an AlignedHeapSegment -- even though |
38 | | /// some prefix of the storage is reserved for auxiliary data structures. |
39 | | static constexpr size_t size(); |
40 | | |
41 | | /// Translate the given address, which is required to be within the |
42 | | /// covered range of the MarkBitArray, to a 0-based index in the |
43 | | /// array. (Rounds down to the nearest aligned address.) |
44 | | inline size_t addressToIndex(const void *p) const; |
45 | | |
46 | | /// Translate the given index, which is required to be within the |
47 | | /// range of the array, to an external address. |
48 | | inline char *indexToAddress(size_t ind) const; |
49 | | |
50 | | /// Returns the bit for the given index, which is required to be within the |
51 | | /// range of the array. |
52 | | inline bool at(size_t ind) const; |
53 | | |
54 | | /// Marks the bit for the given index, which is required to be within the |
55 | | /// range of the array. |
56 | | inline void mark(size_t ind); |
57 | | |
58 | | /// Clears the bit array. |
59 | | inline void clear(); |
60 | | |
61 | | /// Sets all bits to true. |
62 | | inline void markAll(); |
63 | | |
64 | | /// Finds the next bit in the MarkBitArray that is set to 1, starting at and |
65 | | /// including \p ind, the index from which to begin searching. Returns one |
66 | | /// past the last array index if there is not another marked bit. |
67 | | inline size_t findNextMarkedBitFrom(size_t ind); |
68 | | |
69 | | /// Finds the next bit in the MarkBitArray that is set to 0, starting at and |
70 | | /// including \p ind, the index from which to begin searching. Returns one |
71 | | /// past the last array index if there is not another marked bit. |
72 | | inline size_t findNextUnmarkedBitFrom(size_t ind); |
73 | | |
74 | | /// Finds the previous bit in the MarkBitArray that is set to 1, starting at |
75 | | /// and |
76 | | /// including \p ind, the index from which to begin searching. Returns one |
77 | | /// past the last array index if there is not another marked bit. |
78 | | inline size_t findPrevMarkedBitFrom(size_t ind); |
79 | | |
80 | | /// Finds the previous bit in the MarkBitArray that is set to 0, starting at |
81 | | /// and including \p ind, the index from which to begin searching. Returns one |
82 | | /// past the last array index if there is not another marked bit. |
83 | | inline size_t findPrevUnmarkedBitFrom(size_t ind); |
84 | | |
85 | | // Mangling scheme used by MSVC encode public/private into the name. |
86 | | // As a result, vanilla "ifdef public" trick leads to link errors. |
87 | | #if defined(UNIT_TEST) || defined(_MSC_VER) |
88 | | public: |
89 | | #else |
90 | | private: |
91 | | #endif |
92 | | |
93 | | /// \return The lowest address that can be marked in this array. i.e. The |
94 | | /// lowest address such that |
95 | | /// |
96 | | /// addressToIndex(base()) == 0 |
97 | | /// |
98 | | /// Note that the base address will be strictly less than the address |
99 | | /// corresponding to the start of the allocation region (by at least the width |
100 | | /// of the mark bit array). |
101 | | inline char *base() const; |
102 | | |
103 | | /// The number of bits representing the total number of heap-aligned addresses |
104 | | /// in the AlignedStorage. |
105 | | static constexpr size_t kNumBits = AlignedStorage::size() >> LogHeapAlign; |
106 | | /// Bitset holding the contents of the mark bit array. Align it to the page |
107 | | /// size. |
108 | | BitArray<kNumBits> bitArray_; |
109 | | }; |
110 | | |
111 | 104 | /* static */ constexpr size_t MarkBitArrayNC::size() { |
112 | 104 | return kNumBits; |
113 | 104 | } |
114 | | |
115 | 341k | size_t MarkBitArrayNC::addressToIndex(const void *p) const { |
116 | 341k | assert( |
117 | 341k | base() <= p && p < AlignedStorage::end(base()) && |
118 | 341k | "precondition: argument must be within the covered range"); |
119 | 341k | auto cp = reinterpret_cast<const char *>(p); |
120 | 341k | return (cp - base()) >> LogHeapAlign; |
121 | 341k | } |
122 | | |
123 | 0 | char *MarkBitArrayNC::indexToAddress(size_t ind) const { |
124 | 0 | assert(ind < kNumBits && "ind must be within the index range"); |
125 | 0 | char *res = base() + (ind << LogHeapAlign); |
126 | 0 |
|
127 | 0 | assert( |
128 | 0 | base() <= res && res < AlignedStorage::end(base()) && |
129 | 0 | "result must be within the covered range."); |
130 | 0 | return res; |
131 | 0 | } |
132 | | |
133 | 80.9k | bool MarkBitArrayNC::at(size_t ind) const { |
134 | 80.9k | assert(ind < kNumBits && "precondition: ind must be within the index range"); |
135 | 80.9k | return bitArray_.at(ind); |
136 | 80.9k | } |
137 | | |
138 | 260k | void MarkBitArrayNC::mark(size_t ind) { |
139 | 260k | assert(ind < kNumBits && "precondition: ind must be within the index range"); |
140 | 260k | bitArray_.set(ind, true); |
141 | 260k | } |
142 | | |
143 | 1 | void MarkBitArrayNC::clear() { |
144 | 1 | bitArray_.reset(); |
145 | 1 | } |
146 | | |
147 | 226 | void MarkBitArrayNC::markAll() { |
148 | 226 | bitArray_.set(); |
149 | 226 | } |
150 | | |
151 | 0 | size_t MarkBitArrayNC::findNextMarkedBitFrom(size_t ind) { |
152 | 0 | return bitArray_.findNextSetBitFrom(ind); |
153 | 0 | } |
154 | | |
155 | 104 | size_t MarkBitArrayNC::findNextUnmarkedBitFrom(size_t ind) { |
156 | 104 | return bitArray_.findNextZeroBitFrom(ind); |
157 | 104 | } |
158 | | |
159 | 0 | size_t MarkBitArrayNC::findPrevMarkedBitFrom(size_t ind) { |
160 | 0 | return bitArray_.findPrevSetBitFrom(ind); |
161 | 0 | } |
162 | | |
163 | 0 | size_t MarkBitArrayNC::findPrevUnmarkedBitFrom(size_t ind) { |
164 | 0 | return bitArray_.findPrevZeroBitFrom(ind); |
165 | 0 | } |
166 | | |
167 | 1.02M | char *MarkBitArrayNC::base() const { |
168 | | // As we know the mark bit array is laid out inline before the allocation |
169 | | // region of its aligned heap segment, we can use its own this pointer as the |
170 | | // base address. It is safe to cast away the const because we never use the |
171 | | // resulting pointer to index back into the array, but rather to index past it |
172 | | // into the allocation region. |
173 | 1.02M | return const_cast<char *>(reinterpret_cast<const char *>(this)); |
174 | 1.02M | } |
175 | | |
176 | | } // namespace vm |
177 | | } // namespace hermes |
178 | | |
179 | | #endif // HERMES_VM_MARKBITARRAYNC_H |