v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
bit-vector.h
Go to the documentation of this file.
1// Copyright 2012 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_UTILS_BIT_VECTOR_H_
6#define V8_UTILS_BIT_VECTOR_H_
7
8#include <algorithm>
9
10#include "src/base/bits.h"
11#include "src/zone/zone.h"
12
13namespace v8 {
14namespace internal {
15
17 public:
18 // Iterator for the elements of this BitVector.
19 class Iterator {
20 public:
22 int bit_in_word = current_index_ & (kDataBits - 1);
23 if (bit_in_word < kDataBits - 1) {
24 uintptr_t remaining_bits = *ptr_ >> (bit_in_word + 1);
25 if (remaining_bits) {
26 int next_bit_in_word = base::bits::CountTrailingZeros(remaining_bits);
27 current_index_ += next_bit_in_word + 1;
28 return;
29 }
30 }
31
32 // Move {current_index_} down to the beginning of the current word, before
33 // starting to search for the next non-empty word.
34 current_index_ = RoundDown(current_index_, kDataBits);
35 do {
36 ++ptr_;
37 current_index_ += kDataBits;
38 if (ptr_ == end_) return;
39 } while (*ptr_ == 0);
40
41 uintptr_t trailing_zeros = base::bits::CountTrailingZeros(*ptr_);
42 current_index_ += trailing_zeros;
43 }
44
45 int operator*() const {
47 DCHECK(target_->Contains(current_index_));
48 return current_index_;
49 }
50
51 bool operator==(const Iterator& other) const {
52 DCHECK_EQ(target_, other.target_);
53 DCHECK_EQ(end_, other.end_);
54 DCHECK_IMPLIES(current_index_ == other.current_index_,
55 ptr_ == other.ptr_);
56 return current_index_ == other.current_index_;
57 }
58
59 bool operator!=(const Iterator& other) const { return !(*this == other); }
60
61 private:
62 static constexpr struct StartTag {
63 } kStartTag = {};
64 static constexpr struct EndTag {
65 } kEndTag = {};
66
67 explicit Iterator(const BitVector* target, StartTag)
68 :
69#ifdef DEBUG
70 target_(target),
71#endif
72 ptr_(target->data_begin_),
73 end_(target->data_end_),
74 current_index_(0) {
76 while (*ptr_ == 0) {
77 ++ptr_;
78 current_index_ += kDataBits;
79 if (ptr_ == end_) return;
80 }
81 current_index_ += base::bits::CountTrailingZeros(*ptr_);
82 }
83
84 explicit Iterator(const BitVector* target, EndTag)
85 :
86#ifdef DEBUG
87 target_(target),
88#endif
89 ptr_(target->data_end_),
90 end_(target->data_end_),
91 current_index_(target->data_length() * kDataBits) {
92 }
93
94#ifdef DEBUG
95 const BitVector* target_;
96#endif
97 uintptr_t* ptr_;
98 uintptr_t* end_;
100
101 friend class BitVector;
102 };
103
104 static constexpr int kDataBits = kBitsPerSystemPointer;
105 static constexpr int kDataBitShift = kBitsPerSystemPointerLog2;
106
107 BitVector() = default;
108
109 BitVector(int length, Zone* zone) : length_(length) {
110 DCHECK_LE(0, length);
111 int data_length = (length + kDataBits - 1) >> kDataBitShift;
112 if (data_length > 1) {
113 data_.ptr_ = zone->AllocateArray<uintptr_t>(data_length);
114 std::fill_n(data_.ptr_, data_length, 0);
115 data_begin_ = data_.ptr_;
116 data_end_ = data_begin_ + data_length;
117 }
118 }
119
120 BitVector(const BitVector& other, Zone* zone)
121 : length_(other.length_), data_(other.data_.inline_) {
122 if (!other.is_inline()) {
123 int data_length = other.data_length();
124 DCHECK_LT(1, data_length);
125 data_.ptr_ = zone->AllocateArray<uintptr_t>(data_length);
126 data_begin_ = data_.ptr_;
127 data_end_ = data_begin_ + data_length;
128 std::copy_n(other.data_begin_, data_length, data_begin_);
129 }
130 }
131
132 // Disallow copy and copy-assignment.
133 BitVector(const BitVector&) = delete;
134 BitVector& operator=(const BitVector&) = delete;
135
136 BitVector(BitVector&& other) V8_NOEXCEPT { *this = std::move(other); }
137
139 length_ = other.length_;
140 data_ = other.data_;
141 if (other.is_inline()) {
142 data_begin_ = &data_.inline_;
143 data_end_ = data_begin_ + other.data_length();
144 } else {
145 data_begin_ = other.data_begin_;
146 data_end_ = other.data_end_;
147 // Reset other to inline.
148 other.length_ = 0;
149 other.data_begin_ = &other.data_.inline_;
150 other.data_end_ = other.data_begin_ + 1;
151 }
152 return *this;
153 }
154
155 void CopyFrom(const BitVector& other) {
156 DCHECK_EQ(other.length(), length());
157 DCHECK_EQ(is_inline(), other.is_inline());
158 std::copy_n(other.data_begin_, data_length(), data_begin_);
159 }
160
161 void Resize(int new_length, Zone* zone) {
163 int old_data_length = data_length();
164 DCHECK_LE(1, old_data_length);
165 int new_data_length = (new_length + kDataBits - 1) >> kDataBitShift;
166 if (new_data_length > old_data_length) {
167 uintptr_t* new_data = zone->AllocateArray<uintptr_t>(new_data_length);
168
169 // Copy over the data.
170 std::copy_n(data_begin_, old_data_length, new_data);
171 // Zero out the rest of the data.
172 std::fill(new_data + old_data_length, new_data + new_data_length, 0);
173
174 data_begin_ = new_data;
175 data_end_ = new_data + new_data_length;
176 }
178 }
179
180 bool Contains(int i) const {
181 DCHECK(i >= 0 && i < length());
182 return (data_begin_[word(i)] & bit(i)) != 0;
183 }
184
185 void Add(int i) {
186 DCHECK(i >= 0 && i < length());
187 data_begin_[word(i)] |= bit(i);
188 }
189
190 void AddAll() {
191 // TODO(leszeks): This sets bits outside of the length of this bit-vector,
192 // which is observable if we resize it or copy from it. If this is a
193 // problem, we should clear the high bits either on add, or on resize/copy.
194 memset(data_begin_, -1, sizeof(*data_begin_) * data_length());
195 }
196
197 void Remove(int i) {
198 DCHECK(i >= 0 && i < length());
199 data_begin_[word(i)] &= ~bit(i);
200 }
201
202 void Union(const BitVector& other) {
203 DCHECK_EQ(other.length(), length());
204 for (int i = 0; i < data_length(); i++) {
205 data_begin_[i] |= other.data_begin_[i];
206 }
207 }
208
209 bool UnionIsChanged(const BitVector& other) {
210 DCHECK(other.length() == length());
211 bool changed = false;
212 for (int i = 0; i < data_length(); i++) {
213 uintptr_t old_data = data_begin_[i];
214 data_begin_[i] |= other.data_begin_[i];
215 if (data_begin_[i] != old_data) changed = true;
216 }
217 return changed;
218 }
219
220 void Intersect(const BitVector& other) {
221 DCHECK(other.length() == length());
222 for (int i = 0; i < data_length(); i++) {
223 data_begin_[i] &= other.data_begin_[i];
224 }
225 }
226
227 bool IntersectIsChanged(const BitVector& other) {
228 DCHECK(other.length() == length());
229 bool changed = false;
230 for (int i = 0; i < data_length(); i++) {
231 uintptr_t old_data = data_begin_[i];
232 data_begin_[i] &= other.data_begin_[i];
233 if (data_begin_[i] != old_data) changed = true;
234 }
235 return changed;
236 }
237
238 void Subtract(const BitVector& other) {
239 DCHECK(other.length() == length());
240 for (int i = 0; i < data_length(); i++) {
241 data_begin_[i] &= ~other.data_begin_[i];
242 }
243 }
244
245 void Clear() { std::fill_n(data_begin_, data_length(), 0); }
246
247 bool IsEmpty() const {
248 return std::all_of(data_begin_, data_end_, std::logical_not<uintptr_t>{});
249 }
250
251 bool Equals(const BitVector& other) const {
252 return std::equal(data_begin_, data_end_, other.data_begin_);
253 }
254
255 int Count() const;
256
257 int length() const { return length_; }
258
259 Iterator begin() const { return Iterator(this, Iterator::kStartTag); }
260
261 Iterator end() const { return Iterator(this, Iterator::kEndTag); }
262
263#ifdef DEBUG
264 void Print() const;
265#endif
266
267 private:
269 uintptr_t* ptr_; // valid if >1 machine word is needed
270 uintptr_t inline_; // valid if <=1 machine word is needed
271
272 explicit DataStorage(uintptr_t value) : inline_(value) {}
273 };
274
275 bool is_inline() const { return data_begin_ == &data_.inline_; }
276 int data_length() const { return static_cast<int>(data_end_ - data_begin_); }
277
278 V8_INLINE static int word(int index) {
279 V8_ASSUME(index >= 0);
280 return index >> kDataBitShift;
281 }
282 V8_INLINE static uintptr_t bit(int index) {
283 return uintptr_t{1} << (index & (kDataBits - 1));
284 }
285
286 int length_ = 0;
288 uintptr_t* data_begin_ = &data_.inline_;
289 uintptr_t* data_end_ = &data_.inline_ + 1;
290};
291
293 public:
294 GrowableBitVector() = default;
295 GrowableBitVector(int length, Zone* zone) : bits_(length, zone) {}
296
297 bool Contains(int value) const {
298 if (!InBitsRange(value)) return false;
299 return bits_.Contains(value);
300 }
301
302 void Add(int value, Zone* zone) {
303 if (V8_UNLIKELY(!InBitsRange(value))) Grow(value, zone);
304 bits_.Add(value);
305 }
306
307 bool IsEmpty() const { return bits_.IsEmpty(); }
308
309 void Clear() { bits_.Clear(); }
310
311 int length() const { return bits_.length(); }
312
313 bool Equals(const GrowableBitVector& other) const {
314 return length() == other.length() && bits_.Equals(other.bits_);
315 }
316
317 BitVector::Iterator begin() const { return bits_.begin(); }
318
319 BitVector::Iterator end() const { return bits_.end(); }
320
321 private:
322 static constexpr int kInitialLength = 1024;
323
324 // The allocated size is always a power of two, and needs to be strictly
325 // bigger than the biggest contained value.
326 static constexpr int kMaxSupportedValue = (1 << 30) - 1;
327
328 bool InBitsRange(int value) const { return bits_.length() > value; }
329
330 V8_NOINLINE void Grow(int needed_value, Zone* zone) {
331 DCHECK(!InBitsRange(needed_value));
332 // Ensure that {RoundUpToPowerOfTwo32} does not overflow {int} range.
333 CHECK_GE(kMaxSupportedValue, needed_value);
334 int new_length = std::max(
336 static_cast<uint32_t>(needed_value + 1))));
337 bits_.Resize(new_length, zone);
338 }
339
341};
342
343} // namespace internal
344} // namespace v8
345
346#endif // V8_UTILS_BIT_VECTOR_H_
uint8_t data_[MAX_STACK_LENGTH]
bool operator==(const Iterator &other) const
Definition bit-vector.h:51
Iterator(const BitVector *target, StartTag)
Definition bit-vector.h:67
V8_EXPORT_PRIVATE void operator++()
Definition bit-vector.h:21
bool operator!=(const Iterator &other) const
Definition bit-vector.h:59
Iterator(const BitVector *target, EndTag)
Definition bit-vector.h:84
void Subtract(const BitVector &other)
Definition bit-vector.h:238
Iterator end() const
Definition bit-vector.h:261
static V8_INLINE uintptr_t bit(int index)
Definition bit-vector.h:282
bool IntersectIsChanged(const BitVector &other)
Definition bit-vector.h:227
BitVector & operator=(const BitVector &)=delete
BitVector & operator=(BitVector &&other) V8_NOEXCEPT
Definition bit-vector.h:138
bool UnionIsChanged(const BitVector &other)
Definition bit-vector.h:209
void CopyFrom(const BitVector &other)
Definition bit-vector.h:155
void Intersect(const BitVector &other)
Definition bit-vector.h:220
BitVector(const BitVector &)=delete
BitVector(const BitVector &other, Zone *zone)
Definition bit-vector.h:120
BitVector(BitVector &&other) V8_NOEXCEPT
Definition bit-vector.h:136
bool Contains(int i) const
Definition bit-vector.h:180
static V8_INLINE int word(int index)
Definition bit-vector.h:278
void Resize(int new_length, Zone *zone)
Definition bit-vector.h:161
Iterator begin() const
Definition bit-vector.h:259
void Union(const BitVector &other)
Definition bit-vector.h:202
bool Equals(const BitVector &other) const
Definition bit-vector.h:251
BitVector(int length, Zone *zone)
Definition bit-vector.h:109
V8_NOINLINE void Grow(int needed_value, Zone *zone)
Definition bit-vector.h:330
static constexpr int kMaxSupportedValue
Definition bit-vector.h:326
BitVector::Iterator end() const
Definition bit-vector.h:319
static constexpr int kInitialLength
Definition bit-vector.h:322
bool Contains(int value) const
Definition bit-vector.h:297
BitVector::Iterator begin() const
Definition bit-vector.h:317
bool Equals(const GrowableBitVector &other) const
Definition bit-vector.h:313
bool InBitsRange(int value) const
Definition bit-vector.h:328
GrowableBitVector(int length, Zone *zone)
Definition bit-vector.h:295
void Add(int value, Zone *zone)
Definition bit-vector.h:302
T * AllocateArray(size_t length)
Definition zone.h:127
Node ** ptr_
const v8::base::TimeTicks end_
Definition sweeper.cc:54
const int length_
Definition mul-fft.cc:473
V8_BASE_EXPORT constexpr uint32_t RoundUpToPowerOfTwo32(uint32_t value)
Definition bits.h:219
constexpr int kBitsPerSystemPointer
Definition globals.h:684
return value
Definition map-inl.h:893
constexpr int kBitsPerSystemPointerLog2
Definition globals.h:685
#define V8_NOEXCEPT
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_GE(lhs, rhs)
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
constexpr T RoundDown(T x, intptr_t m)
Definition macros.h:371
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_INLINE
Definition v8config.h:500
#define V8_ASSUME
Definition v8config.h:533
#define V8_UNLIKELY(condition)
Definition v8config.h:660
#define V8_NOINLINE
Definition v8config.h:586