Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_MARKING_H | 5 #ifndef V8_MARKING_H |
| 6 #define V8_MARKING_H | 6 #define V8_MARKING_H |
| 7 | 7 |
| 8 #include "src/base/atomic-utils.h" | |
| 8 #include "src/utils.h" | 9 #include "src/utils.h" |
| 9 | 10 |
| 10 namespace v8 { | 11 namespace v8 { |
| 11 namespace internal { | 12 namespace internal { |
| 12 | 13 |
| 13 class MarkBit { | 14 class MarkBit { |
| 14 public: | 15 public: |
| 15 typedef uint32_t CellType; | 16 typedef uint32_t CellType; |
|
Michael Lippautz
2017/03/06 13:52:54
nit: Can we have a static_assert that sizeof(CellT
Hannes Payer (out of office)
2017/03/08 14:12:57
Done.
| |
| 16 | 17 |
| 17 inline MarkBit(CellType* cell, CellType mask) : cell_(cell), mask_(mask) {} | 18 enum ModificationMode { ATOMIC, NON_ATOMIC }; |
|
Michael Lippautz
2017/03/06 13:52:54
You could make an
enum class ModicationMode
out
Hannes Payer (out of office)
2017/03/08 14:12:57
I kind of like it to keep it in the MarkBit class
| |
| 19 | |
| 20 inline MarkBit(base::Atomic32* cell, CellType mask) : cell_(cell) { | |
| 21 mask_ = static_cast<base::Atomic32>(mask); | |
| 22 } | |
| 18 | 23 |
| 19 #ifdef DEBUG | 24 #ifdef DEBUG |
| 20 bool operator==(const MarkBit& other) { | 25 bool operator==(const MarkBit& other) { |
| 21 return cell_ == other.cell_ && mask_ == other.mask_; | 26 return cell_ == other.cell_ && mask_ == other.mask_; |
| 22 } | 27 } |
| 23 #endif | 28 #endif |
| 24 | 29 |
| 25 private: | 30 private: |
| 26 inline CellType* cell() { return cell_; } | |
| 27 inline CellType mask() { return mask_; } | |
| 28 | |
| 29 inline MarkBit Next() { | 31 inline MarkBit Next() { |
| 30 CellType new_mask = mask_ << 1; | 32 CellType new_mask = mask_ << 1; |
| 31 if (new_mask == 0) { | 33 if (new_mask == 0) { |
| 32 return MarkBit(cell_ + 1, 1); | 34 return MarkBit(cell_ + 1, 1); |
| 33 } else { | 35 } else { |
| 34 return MarkBit(cell_, new_mask); | 36 return MarkBit(cell_, new_mask); |
| 35 } | 37 } |
| 36 } | 38 } |
| 37 | 39 |
| 38 inline void Set() { *cell_ |= mask_; } | 40 template <ModificationMode mode> |
| 39 inline bool Get() { return (*cell_ & mask_) != 0; } | 41 inline bool Set() { |
| 40 inline void Clear() { *cell_ &= ~mask_; } | 42 if (mode == ATOMIC) { |
| 43 base::Atomic32 old_value; | |
| 44 base::Atomic32 new_value; | |
| 45 do { | |
| 46 old_value = base::NoBarrier_Load(cell_); | |
| 47 if (old_value & mask_) return false; | |
| 48 new_value = old_value | mask_; | |
| 49 } while (base::Release_CompareAndSwap(cell_, old_value, new_value) != | |
| 50 old_value); | |
| 51 } else { | |
| 52 *cell_ |= mask_; | |
| 53 } | |
| 54 return true; | |
| 55 } | |
| 41 | 56 |
| 42 CellType* cell_; | 57 template <ModificationMode mode> |
| 43 CellType mask_; | 58 inline bool Get() { |
| 59 if (mode == ATOMIC) { | |
| 60 return (base::Acquire_Load(cell_) & mask_) != 0; | |
| 61 } else { | |
| 62 return (base::NoBarrier_Load(cell_) & mask_) != 0; | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 template <ModificationMode mode> | |
| 67 inline bool Clear() { | |
| 68 if (mode == ATOMIC) { | |
| 69 base::Atomic32 old_value; | |
| 70 base::Atomic32 new_value; | |
| 71 do { | |
| 72 old_value = base::NoBarrier_Load(cell_); | |
| 73 if (!(old_value & mask_)) return false; | |
| 74 new_value = old_value & ~mask_; | |
| 75 } while (base::Release_CompareAndSwap(cell_, old_value, new_value) != | |
| 76 old_value); | |
| 77 } else { | |
| 78 *cell_ &= ~mask_; | |
| 79 } | |
| 80 return true; | |
| 81 } | |
| 82 | |
| 83 base::Atomic32* cell_; | |
| 84 base::Atomic32 mask_; | |
| 44 | 85 |
| 45 friend class IncrementalMarking; | 86 friend class IncrementalMarking; |
| 46 friend class Marking; | 87 friend class Marking; |
| 47 }; | 88 }; |
| 48 | 89 |
| 49 // Bitmap is a sequence of cells each containing fixed number of bits. | 90 // Bitmap is a sequence of cells each containing fixed number of bits. |
| 50 class Bitmap { | 91 class Bitmap { |
| 51 public: | 92 public: |
| 52 static const uint32_t kBitsPerCell = 32; | 93 static const uint32_t kBitsPerCell = 32; |
| 53 static const uint32_t kBitsPerCellLog2 = 5; | 94 static const uint32_t kBitsPerCellLog2 = 5; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 | 133 |
| 93 INLINE(Address address()) { return reinterpret_cast<Address>(this); } | 134 INLINE(Address address()) { return reinterpret_cast<Address>(this); } |
| 94 | 135 |
| 95 INLINE(static Bitmap* FromAddress(Address addr)) { | 136 INLINE(static Bitmap* FromAddress(Address addr)) { |
| 96 return reinterpret_cast<Bitmap*>(addr); | 137 return reinterpret_cast<Bitmap*>(addr); |
| 97 } | 138 } |
| 98 | 139 |
| 99 inline MarkBit MarkBitFromIndex(uint32_t index) { | 140 inline MarkBit MarkBitFromIndex(uint32_t index) { |
| 100 MarkBit::CellType mask = 1u << IndexInCell(index); | 141 MarkBit::CellType mask = 1u << IndexInCell(index); |
| 101 MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2); | 142 MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2); |
| 102 return MarkBit(cell, mask); | 143 return MarkBit(reinterpret_cast<base::Atomic32*>(cell), mask); |
| 103 } | 144 } |
| 104 | 145 |
| 105 void Clear() { | 146 void Clear() { |
| 106 for (int i = 0; i < CellsCount(); i++) cells()[i] = 0; | 147 for (int i = 0; i < CellsCount(); i++) cells()[i] = 0; |
| 107 } | 148 } |
| 108 | 149 |
| 109 // Sets all bits in the range [start_index, end_index). | 150 // Sets all bits in the range [start_index, end_index). |
| 110 void SetRange(uint32_t start_index, uint32_t end_index) { | 151 void SetRange(uint32_t start_index, uint32_t end_index) { |
| 111 unsigned int start_cell_index = start_index >> Bitmap::kBitsPerCellLog2; | 152 unsigned int start_cell_index = start_index >> Bitmap::kBitsPerCellLog2; |
| 112 MarkBit::CellType start_index_mask = 1u << Bitmap::IndexInCell(start_index); | 153 MarkBit::CellType start_index_mask = 1u << Bitmap::IndexInCell(start_index); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 if (cells()[i] != 0) { | 303 if (cells()[i] != 0) { |
| 263 return false; | 304 return false; |
| 264 } | 305 } |
| 265 } | 306 } |
| 266 return true; | 307 return true; |
| 267 } | 308 } |
| 268 }; | 309 }; |
| 269 | 310 |
| 270 class Marking : public AllStatic { | 311 class Marking : public AllStatic { |
| 271 public: | 312 public: |
| 313 // TODO(hpayer): The current mark bit operations use as default NON_ATOMIC | |
| 314 // mode for access. We should remove the default value or switch it with | |
| 315 // ATOMIC as soon we add concurrency. | |
| 316 | |
| 272 // Impossible markbits: 01 | 317 // Impossible markbits: 01 |
| 273 static const char* kImpossibleBitPattern; | 318 static const char* kImpossibleBitPattern; |
| 319 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> | |
| 274 INLINE(static bool IsImpossible(MarkBit mark_bit)) { | 320 INLINE(static bool IsImpossible(MarkBit mark_bit)) { |
| 275 return !mark_bit.Get() && mark_bit.Next().Get(); | 321 return !mark_bit.Get<mode>() && mark_bit.Next().Get<mode>(); |
|
ulan
2017/03/06 14:51:33
Atomic version can return false positive if betwee
Hannes Payer (out of office)
2017/03/08 14:12:57
This function is still useful. I made it safe for
| |
| 276 } | 322 } |
| 277 | 323 |
| 278 // Black markbits: 11 | 324 // Black markbits: 11 |
| 279 static const char* kBlackBitPattern; | 325 static const char* kBlackBitPattern; |
| 326 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> | |
| 280 INLINE(static bool IsBlack(MarkBit mark_bit)) { | 327 INLINE(static bool IsBlack(MarkBit mark_bit)) { |
| 281 return mark_bit.Get() && mark_bit.Next().Get(); | 328 return mark_bit.Get<mode>() && mark_bit.Next().Get<mode>(); |
| 282 } | 329 } |
| 283 | 330 |
| 284 // White markbits: 00 - this is required by the mark bit clearer. | 331 // White markbits: 00 - this is required by the mark bit clearer. |
| 285 static const char* kWhiteBitPattern; | 332 static const char* kWhiteBitPattern; |
| 333 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> | |
| 286 INLINE(static bool IsWhite(MarkBit mark_bit)) { | 334 INLINE(static bool IsWhite(MarkBit mark_bit)) { |
| 287 DCHECK(!IsImpossible(mark_bit)); | 335 DCHECK(!IsImpossible(mark_bit)); |
| 288 return !mark_bit.Get(); | 336 return !mark_bit.Get<mode>(); |
| 289 } | 337 } |
| 290 | 338 |
| 291 // Grey markbits: 10 | 339 // Grey markbits: 10 |
| 292 static const char* kGreyBitPattern; | 340 static const char* kGreyBitPattern; |
| 341 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> | |
| 293 INLINE(static bool IsGrey(MarkBit mark_bit)) { | 342 INLINE(static bool IsGrey(MarkBit mark_bit)) { |
| 294 return mark_bit.Get() && !mark_bit.Next().Get(); | 343 return mark_bit.Get<mode>() && !mark_bit.Next().Get<mode>(); |
| 295 } | 344 } |
| 296 | 345 |
| 297 // IsBlackOrGrey assumes that the first bit is set for black or grey | 346 // IsBlackOrGrey assumes that the first bit is set for black or grey |
| 298 // objects. | 347 // objects. |
| 299 INLINE(static bool IsBlackOrGrey(MarkBit mark_bit)) { return mark_bit.Get(); } | 348 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> |
| 300 | 349 INLINE(static bool IsBlackOrGrey(MarkBit mark_bit)) { |
| 301 INLINE(static void MarkWhite(MarkBit markbit)) { | 350 return mark_bit.Get<mode>(); |
| 302 markbit.Clear(); | |
| 303 markbit.Next().Clear(); | |
| 304 } | 351 } |
| 305 | 352 |
| 306 INLINE(static void BlackToGrey(MarkBit markbit)) { | 353 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> |
| 307 DCHECK(IsBlack(markbit)); | 354 INLINE(static bool MarkWhite(MarkBit markbit)) { |
|
ulan
2017/03/06 14:51:33
All functions that move the color in black -> grey
Hannes Payer (out of office)
2017/03/08 14:12:57
Done.
Why is BlackToGrey a problem?
| |
| 308 markbit.Next().Clear(); | 355 if (!markbit.Clear<mode>()) return false; |
| 356 return markbit.Next().Clear<mode>(); | |
| 309 } | 357 } |
| 310 | 358 |
| 311 INLINE(static void WhiteToGrey(MarkBit markbit)) { | 359 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> |
| 312 DCHECK(IsWhite(markbit)); | 360 INLINE(static bool BlackToGrey(MarkBit markbit)) { |
| 313 markbit.Set(); | 361 DCHECK(IsBlack(markbit)); |
| 362 return markbit.Next().Clear<mode>(); | |
| 314 } | 363 } |
| 315 | 364 |
| 316 INLINE(static void WhiteToBlack(MarkBit markbit)) { | 365 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> |
| 366 INLINE(static bool WhiteToGrey(MarkBit markbit)) { | |
| 317 DCHECK(IsWhite(markbit)); | 367 DCHECK(IsWhite(markbit)); |
| 318 markbit.Set(); | 368 return markbit.Set<mode>(); |
| 319 markbit.Next().Set(); | |
| 320 } | 369 } |
| 321 | 370 |
| 322 INLINE(static void GreyToBlack(MarkBit markbit)) { | 371 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> |
| 372 INLINE(static bool WhiteToBlack(MarkBit markbit)) { | |
| 373 DCHECK(IsWhite(markbit)); | |
| 374 if (!markbit.Set<mode>()) return false; | |
| 375 return markbit.Next().Set<mode>(); | |
| 376 } | |
| 377 | |
| 378 template <MarkBit::ModificationMode mode = MarkBit::NON_ATOMIC> | |
| 379 INLINE(static bool GreyToBlack(MarkBit markbit)) { | |
| 323 DCHECK(IsGrey(markbit)); | 380 DCHECK(IsGrey(markbit)); |
| 324 markbit.Next().Set(); | 381 return markbit.Next().Set<mode>(); |
| 325 } | 382 } |
| 326 | 383 |
| 327 enum ObjectColor { | 384 enum ObjectColor { |
| 328 BLACK_OBJECT, | 385 BLACK_OBJECT, |
| 329 WHITE_OBJECT, | 386 WHITE_OBJECT, |
| 330 GREY_OBJECT, | 387 GREY_OBJECT, |
| 331 IMPOSSIBLE_COLOR | 388 IMPOSSIBLE_COLOR |
| 332 }; | 389 }; |
| 333 | 390 |
| 334 static const char* ColorName(ObjectColor color) { | 391 static const char* ColorName(ObjectColor color) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 354 } | 411 } |
| 355 | 412 |
| 356 private: | 413 private: |
| 357 DISALLOW_IMPLICIT_CONSTRUCTORS(Marking); | 414 DISALLOW_IMPLICIT_CONSTRUCTORS(Marking); |
| 358 }; | 415 }; |
| 359 | 416 |
| 360 } // namespace internal | 417 } // namespace internal |
| 361 } // namespace v8 | 418 } // namespace v8 |
| 362 | 419 |
| 363 #endif // V8_MARKING_H_ | 420 #endif // V8_MARKING_H_ |
| OLD | NEW |