Coverage Report

Created: 2025-12-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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