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 |