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_BIT_VECTOR_H_ 6 #define V8_BIT_VECTOR_H_ 7 8 #include "src/allocation.h" 9 #include "src/zone/zone.h" 10 11 namespace v8 { 12 namespace internal { 13 14 class BitVector : public ZoneObject { 15 public: 16 union DataStorage { 17 uintptr_t* ptr_; // valid if data_length_ > 1 18 uintptr_t inline_; // valid if data_length_ == 1 19 DataStorage(uintptr_t value)20 DataStorage(uintptr_t value) : inline_(value) {} 21 }; 22 23 // Iterator for the elements of this BitVector. 24 class Iterator BASE_EMBEDDED { 25 public: Iterator(BitVector * target)26 explicit Iterator(BitVector* target) 27 : target_(target), 28 current_index_(0), 29 current_value_(target->is_inline() ? target->data_.inline_ 30 : target->data_.ptr_[0]), 31 current_(-1) { 32 Advance(); 33 } ~Iterator()34 ~Iterator() {} 35 Done()36 bool Done() const { return current_index_ >= target_->data_length_; } 37 void Advance(); 38 Current()39 int Current() const { 40 DCHECK(!Done()); 41 return current_; 42 } 43 44 private: SkipZeroBytes(uintptr_t val)45 uintptr_t SkipZeroBytes(uintptr_t val) { 46 while ((val & 0xFF) == 0) { 47 val >>= 8; 48 current_ += 8; 49 } 50 return val; 51 } SkipZeroBits(uintptr_t val)52 uintptr_t SkipZeroBits(uintptr_t val) { 53 while ((val & 0x1) == 0) { 54 val >>= 1; 55 current_++; 56 } 57 return val; 58 } 59 60 BitVector* target_; 61 int current_index_; 62 uintptr_t current_value_; 63 int current_; 64 65 friend class BitVector; 66 }; 67 68 static const int kDataLengthForInline = 1; 69 static const int kDataBits = kPointerSize * 8; 70 static const int kDataBitShift = kPointerSize == 8 ? 6 : 5; 71 static const uintptr_t kOne = 1; // This saves some static_casts. 72 BitVector()73 BitVector() : length_(0), data_length_(kDataLengthForInline), data_(0) {} 74 BitVector(int length,Zone * zone)75 BitVector(int length, Zone* zone) 76 : length_(length), data_length_(SizeFor(length)), data_(0) { 77 DCHECK_LE(0, length); 78 if (!is_inline()) { 79 data_.ptr_ = zone->NewArray<uintptr_t>(data_length_); 80 Clear(); 81 } 82 // Otherwise, clearing is implicit 83 } 84 BitVector(const BitVector & other,Zone * zone)85 BitVector(const BitVector& other, Zone* zone) 86 : length_(other.length_), 87 data_length_(other.data_length_), 88 data_(other.data_.inline_) { 89 if (!is_inline()) { 90 data_.ptr_ = zone->NewArray<uintptr_t>(data_length_); 91 for (int i = 0; i < other.data_length_; i++) { 92 data_.ptr_[i] = other.data_.ptr_[i]; 93 } 94 } 95 } 96 SizeFor(int length)97 static int SizeFor(int length) { 98 if (length <= kDataBits) { 99 return kDataLengthForInline; 100 } 101 102 int data_length = 1 + ((length - 1) / kDataBits); 103 DCHECK_GT(data_length, kDataLengthForInline); 104 return data_length; 105 } 106 CopyFrom(const BitVector & other)107 void CopyFrom(const BitVector& other) { 108 DCHECK_LE(other.length(), length()); 109 CopyFrom(other.data_, other.data_length_); 110 } 111 Resize(int new_length,Zone * zone)112 void Resize(int new_length, Zone* zone) { 113 DCHECK_GT(new_length, length()); 114 int new_data_length = SizeFor(new_length); 115 if (new_data_length > data_length_) { 116 DataStorage old_data = data_; 117 int old_data_length = data_length_; 118 119 // Make sure the new data length is large enough to need allocation. 120 DCHECK_GT(new_data_length, kDataLengthForInline); 121 data_.ptr_ = zone->NewArray<uintptr_t>(new_data_length); 122 data_length_ = new_data_length; 123 CopyFrom(old_data, old_data_length); 124 } 125 length_ = new_length; 126 } 127 Contains(int i)128 bool Contains(int i) const { 129 DCHECK(i >= 0 && i < length()); 130 uintptr_t block = is_inline() ? data_.inline_ : data_.ptr_[i / kDataBits]; 131 return (block & (kOne << (i % kDataBits))) != 0; 132 } 133 Add(int i)134 void Add(int i) { 135 DCHECK(i >= 0 && i < length()); 136 if (is_inline()) { 137 data_.inline_ |= (kOne << i); 138 } else { 139 data_.ptr_[i / kDataBits] |= (kOne << (i % kDataBits)); 140 } 141 } 142 AddAll()143 void AddAll() { 144 // TODO(leszeks): This sets bits outside of the length of this bit-vector, 145 // which is observable if we resize it or copy from it. If this is a 146 // problem, we should clear the high bits either on add, or on resize/copy. 147 if (is_inline()) { 148 data_.inline_ = -1; 149 } else { 150 memset(data_.ptr_, -1, sizeof(uintptr_t) * data_length_); 151 } 152 } 153 Remove(int i)154 void Remove(int i) { 155 DCHECK(i >= 0 && i < length()); 156 if (is_inline()) { 157 data_.inline_ &= ~(kOne << i); 158 } else { 159 data_.ptr_[i / kDataBits] &= ~(kOne << (i % kDataBits)); 160 } 161 } 162 Union(const BitVector & other)163 void Union(const BitVector& other) { 164 DCHECK(other.length() == length()); 165 if (is_inline()) { 166 DCHECK(other.is_inline()); 167 data_.inline_ |= other.data_.inline_; 168 } else { 169 for (int i = 0; i < data_length_; i++) { 170 data_.ptr_[i] |= other.data_.ptr_[i]; 171 } 172 } 173 } 174 UnionIsChanged(const BitVector & other)175 bool UnionIsChanged(const BitVector& other) { 176 DCHECK(other.length() == length()); 177 if (is_inline()) { 178 DCHECK(other.is_inline()); 179 uintptr_t old_data = data_.inline_; 180 data_.inline_ |= other.data_.inline_; 181 return data_.inline_ != old_data; 182 } else { 183 bool changed = false; 184 for (int i = 0; i < data_length_; i++) { 185 uintptr_t old_data = data_.ptr_[i]; 186 data_.ptr_[i] |= other.data_.ptr_[i]; 187 if (data_.ptr_[i] != old_data) changed = true; 188 } 189 return changed; 190 } 191 } 192 Intersect(const BitVector & other)193 void Intersect(const BitVector& other) { 194 DCHECK(other.length() == length()); 195 if (is_inline()) { 196 DCHECK(other.is_inline()); 197 data_.inline_ &= other.data_.inline_; 198 } else { 199 for (int i = 0; i < data_length_; i++) { 200 data_.ptr_[i] &= other.data_.ptr_[i]; 201 } 202 } 203 } 204 IntersectIsChanged(const BitVector & other)205 bool IntersectIsChanged(const BitVector& other) { 206 DCHECK(other.length() == length()); 207 if (is_inline()) { 208 DCHECK(other.is_inline()); 209 uintptr_t old_data = data_.inline_; 210 data_.inline_ &= other.data_.inline_; 211 return data_.inline_ != old_data; 212 } else { 213 bool changed = false; 214 for (int i = 0; i < data_length_; i++) { 215 uintptr_t old_data = data_.ptr_[i]; 216 data_.ptr_[i] &= other.data_.ptr_[i]; 217 if (data_.ptr_[i] != old_data) changed = true; 218 } 219 return changed; 220 } 221 } 222 Subtract(const BitVector & other)223 void Subtract(const BitVector& other) { 224 DCHECK(other.length() == length()); 225 if (is_inline()) { 226 DCHECK(other.is_inline()); 227 data_.inline_ &= ~other.data_.inline_; 228 } else { 229 for (int i = 0; i < data_length_; i++) { 230 data_.ptr_[i] &= ~other.data_.ptr_[i]; 231 } 232 } 233 } 234 Clear()235 void Clear() { 236 if (is_inline()) { 237 data_.inline_ = 0; 238 } else { 239 for (int i = 0; i < data_length_; i++) { 240 data_.ptr_[i] = 0; 241 } 242 } 243 } 244 IsEmpty()245 bool IsEmpty() const { 246 if (is_inline()) { 247 return data_.inline_ == 0; 248 } else { 249 for (int i = 0; i < data_length_; i++) { 250 if (data_.ptr_[i] != 0) return false; 251 } 252 return true; 253 } 254 } 255 Equals(const BitVector & other)256 bool Equals(const BitVector& other) const { 257 DCHECK(other.length() == length()); 258 if (is_inline()) { 259 DCHECK(other.is_inline()); 260 return data_.inline_ == other.data_.inline_; 261 } else { 262 for (int i = 0; i < data_length_; i++) { 263 if (data_.ptr_[i] != other.data_.ptr_[i]) return false; 264 } 265 return true; 266 } 267 } 268 269 int Count() const; 270 length()271 int length() const { return length_; } 272 273 #ifdef DEBUG 274 void Print(); 275 #endif 276 277 private: 278 int length_; 279 int data_length_; 280 DataStorage data_; 281 is_inline()282 bool is_inline() const { return data_length_ == kDataLengthForInline; } 283 CopyFrom(DataStorage other_data,int other_data_length)284 void CopyFrom(DataStorage other_data, int other_data_length) { 285 DCHECK_LE(other_data_length, data_length_); 286 287 if (is_inline()) { 288 DCHECK_EQ(other_data_length, kDataLengthForInline); 289 data_.inline_ = other_data.inline_; 290 } else if (other_data_length == kDataLengthForInline) { 291 data_.ptr_[0] = other_data.inline_; 292 for (int i = 1; i < data_length_; i++) { 293 data_.ptr_[i] = 0; 294 } 295 } else { 296 for (int i = 0; i < other_data_length; i++) { 297 data_.ptr_[i] = other_data.ptr_[i]; 298 } 299 for (int i = other_data_length; i < data_length_; i++) { 300 data_.ptr_[i] = 0; 301 } 302 } 303 } 304 305 DISALLOW_COPY_AND_ASSIGN(BitVector); 306 }; 307 308 309 class GrowableBitVector BASE_EMBEDDED { 310 public: 311 class Iterator BASE_EMBEDDED { 312 public: Iterator(const GrowableBitVector * target,Zone * zone)313 Iterator(const GrowableBitVector* target, Zone* zone) 314 : it_(target->bits_ == nullptr ? new (zone) BitVector(1, zone) 315 : target->bits_) {} Done()316 bool Done() const { return it_.Done(); } Advance()317 void Advance() { it_.Advance(); } Current()318 int Current() const { return it_.Current(); } 319 320 private: 321 BitVector::Iterator it_; 322 }; 323 GrowableBitVector()324 GrowableBitVector() : bits_(nullptr) {} GrowableBitVector(int length,Zone * zone)325 GrowableBitVector(int length, Zone* zone) 326 : bits_(new (zone) BitVector(length, zone)) {} 327 Contains(int value)328 bool Contains(int value) const { 329 if (!InBitsRange(value)) return false; 330 return bits_->Contains(value); 331 } 332 Add(int value,Zone * zone)333 void Add(int value, Zone* zone) { 334 EnsureCapacity(value, zone); 335 bits_->Add(value); 336 } 337 Union(const GrowableBitVector & other,Zone * zone)338 void Union(const GrowableBitVector& other, Zone* zone) { 339 for (Iterator it(&other, zone); !it.Done(); it.Advance()) { 340 Add(it.Current(), zone); 341 } 342 } 343 Clear()344 void Clear() { 345 if (bits_ != nullptr) bits_->Clear(); 346 } 347 348 private: 349 static const int kInitialLength = 1024; 350 InBitsRange(int value)351 bool InBitsRange(int value) const { 352 return bits_ != nullptr && bits_->length() > value; 353 } 354 EnsureCapacity(int value,Zone * zone)355 void EnsureCapacity(int value, Zone* zone) { 356 if (InBitsRange(value)) return; 357 int new_length = bits_ == nullptr ? kInitialLength : bits_->length(); 358 while (new_length <= value) new_length *= 2; 359 360 if (bits_ == nullptr) { 361 bits_ = new (zone) BitVector(new_length, zone); 362 } else { 363 bits_->Resize(new_length, zone); 364 } 365 } 366 367 BitVector* bits_; 368 }; 369 370 } // namespace internal 371 } // namespace v8 372 373 #endif // V8_BIT_VECTOR_H_ 374