| Index: src/heap/marking.h
|
| diff --git a/src/heap/marking.h b/src/heap/marking.h
|
| index 9cd3907e6d31ebaed9b23c5504034dd58ded0df0..2f89bbe1a1ca3f24cb64aa1b6cf906a96fdb970a 100644
|
| --- a/src/heap/marking.h
|
| +++ b/src/heap/marking.h
|
| @@ -5,6 +5,7 @@
|
| #ifndef V8_MARKING_H
|
| #define V8_MARKING_H
|
|
|
| +#include "src/base/atomic-utils.h"
|
| #include "src/utils.h"
|
|
|
| namespace v8 {
|
| @@ -13,8 +14,13 @@ namespace internal {
|
| class MarkBit {
|
| public:
|
| typedef uint32_t CellType;
|
| + STATIC_ASSERT(sizeof(CellType) == sizeof(base::Atomic32));
|
|
|
| - inline MarkBit(CellType* cell, CellType mask) : cell_(cell), mask_(mask) {}
|
| + enum AccessMode { ATOMIC, NON_ATOMIC };
|
| +
|
| + inline MarkBit(base::Atomic32* cell, CellType mask) : cell_(cell) {
|
| + mask_ = static_cast<base::Atomic32>(mask);
|
| + }
|
|
|
| #ifdef DEBUG
|
| bool operator==(const MarkBit& other) {
|
| @@ -23,9 +29,6 @@ class MarkBit {
|
| #endif
|
|
|
| private:
|
| - inline CellType* cell() { return cell_; }
|
| - inline CellType mask() { return mask_; }
|
| -
|
| inline MarkBit Next() {
|
| CellType new_mask = mask_ << 1;
|
| if (new_mask == 0) {
|
| @@ -35,12 +38,51 @@ class MarkBit {
|
| }
|
| }
|
|
|
| - inline void Set() { *cell_ |= mask_; }
|
| - inline bool Get() { return (*cell_ & mask_) != 0; }
|
| - inline void Clear() { *cell_ &= ~mask_; }
|
| + template <AccessMode mode = NON_ATOMIC>
|
| + inline bool Set() {
|
| + if (mode == ATOMIC) {
|
| + base::Atomic32 old_value;
|
| + base::Atomic32 new_value;
|
| + do {
|
| + old_value = base::NoBarrier_Load(cell_);
|
| + if (old_value & mask_) return false;
|
| + new_value = old_value | mask_;
|
| + } while (base::Release_CompareAndSwap(cell_, old_value, new_value) !=
|
| + old_value);
|
| + } else {
|
| + *cell_ |= mask_;
|
| + }
|
| + return true;
|
| + }
|
|
|
| - CellType* cell_;
|
| - CellType mask_;
|
| + template <AccessMode mode = NON_ATOMIC>
|
| + inline bool Get() {
|
| + if (mode == ATOMIC) {
|
| + return (base::Acquire_Load(cell_) & mask_) != 0;
|
| + } else {
|
| + return (base::NoBarrier_Load(cell_) & mask_) != 0;
|
| + }
|
| + }
|
| +
|
| + template <AccessMode mode = NON_ATOMIC>
|
| + inline bool Clear() {
|
| + if (mode == ATOMIC) {
|
| + base::Atomic32 old_value;
|
| + base::Atomic32 new_value;
|
| + do {
|
| + old_value = base::NoBarrier_Load(cell_);
|
| + if (!(old_value & mask_)) return false;
|
| + new_value = old_value & ~mask_;
|
| + } while (base::Release_CompareAndSwap(cell_, old_value, new_value) !=
|
| + old_value);
|
| + } else {
|
| + *cell_ &= ~mask_;
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + base::Atomic32* cell_;
|
| + base::Atomic32 mask_;
|
|
|
| friend class IncrementalMarking;
|
| friend class ConcurrentMarkingMarkbits;
|
| @@ -100,7 +142,7 @@ class Bitmap {
|
| inline MarkBit MarkBitFromIndex(uint32_t index) {
|
| MarkBit::CellType mask = 1u << IndexInCell(index);
|
| MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2);
|
| - return MarkBit(cell, mask);
|
| + return MarkBit(reinterpret_cast<base::Atomic32*>(cell), mask);
|
| }
|
|
|
| void Clear() {
|
| @@ -270,66 +312,100 @@ class Bitmap {
|
|
|
| class Marking : public AllStatic {
|
| public:
|
| + // TODO(hpayer): The current mark bit operations use as default NON_ATOMIC
|
| + // mode for access. We should remove the default value or switch it with
|
| + // ATOMIC as soon we add concurrency.
|
| +
|
| // Impossible markbits: 01
|
| static const char* kImpossibleBitPattern;
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| INLINE(static bool IsImpossible(MarkBit mark_bit)) {
|
| - return !mark_bit.Get() && mark_bit.Next().Get();
|
| + if (mode == MarkBit::NON_ATOMIC) {
|
| + return !mark_bit.Get<mode>() && mark_bit.Next().Get<mode>();
|
| + }
|
| + // If we are in concurrent mode we can only tell if an object has the
|
| + // impossible bit pattern if we read the first bit again after reading
|
| + // the first and the second bit. If the first bit is till zero and the
|
| + // second bit is one then the object has the impossible bit pattern.
|
| + bool is_impossible = !mark_bit.Get<mode>() && mark_bit.Next().Get<mode>();
|
| + if (is_impossible) {
|
| + return !mark_bit.Get<mode>();
|
| + }
|
| + return false;
|
| }
|
|
|
| // Black markbits: 11
|
| static const char* kBlackBitPattern;
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| INLINE(static bool IsBlack(MarkBit mark_bit)) {
|
| - return mark_bit.Get() && mark_bit.Next().Get();
|
| + return mark_bit.Get<mode>() && mark_bit.Next().Get<mode>();
|
| }
|
|
|
| // White markbits: 00 - this is required by the mark bit clearer.
|
| static const char* kWhiteBitPattern;
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| INLINE(static bool IsWhite(MarkBit mark_bit)) {
|
| DCHECK(!IsImpossible(mark_bit));
|
| - return !mark_bit.Get();
|
| + return !mark_bit.Get<mode>();
|
| }
|
|
|
| // Grey markbits: 10
|
| static const char* kGreyBitPattern;
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| INLINE(static bool IsGrey(MarkBit mark_bit)) {
|
| - return mark_bit.Get() && !mark_bit.Next().Get();
|
| + return mark_bit.Get<mode>() && !mark_bit.Next().Get<mode>();
|
| }
|
|
|
| // IsBlackOrGrey assumes that the first bit is set for black or grey
|
| // objects.
|
| - INLINE(static bool IsBlackOrGrey(MarkBit mark_bit)) { return mark_bit.Get(); }
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| + INLINE(static bool IsBlackOrGrey(MarkBit mark_bit)) {
|
| + return mark_bit.Get<mode>();
|
| + }
|
|
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| INLINE(static void MarkWhite(MarkBit markbit)) {
|
| - markbit.Clear();
|
| - markbit.Next().Clear();
|
| + STATIC_ASSERT(mode == MarkBit::NON_ATOMIC);
|
| + markbit.Clear<mode>();
|
| + markbit.Next().Clear<mode>();
|
| }
|
|
|
| - INLINE(static void MarkGrey(MarkBit markbit)) { markbit.Set(); }
|
| -
|
| + // Warning: this method is not safe in general in concurrent scenarios.
|
| + // If you know that nobody else will change the bits on the given location
|
| + // then you may use it.
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| INLINE(static void MarkBlack(MarkBit markbit)) {
|
| - markbit.Set();
|
| - markbit.Next().Set();
|
| + markbit.Set<mode>();
|
| + markbit.Next().Set<mode>();
|
| }
|
|
|
| - INLINE(static void BlackToGrey(MarkBit markbit)) {
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| + INLINE(static bool BlackToGrey(MarkBit markbit)) {
|
| + STATIC_ASSERT(mode == MarkBit::NON_ATOMIC);
|
| DCHECK(IsBlack(markbit));
|
| - markbit.Next().Clear();
|
| + return markbit.Next().Clear<mode>();
|
| }
|
|
|
| - INLINE(static void WhiteToGrey(MarkBit markbit)) {
|
| - DCHECK(IsWhite(markbit));
|
| - markbit.Set();
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| + INLINE(static bool WhiteToGrey(MarkBit markbit)) {
|
| + DCHECK(mode == MarkBit::ATOMIC || IsWhite(markbit));
|
| + return markbit.Set<mode>();
|
| }
|
|
|
| + // Warning: this method is not safe in general in concurrent scenarios.
|
| + // If you know that nobody else will change the bits on the given location
|
| + // then you may use it.
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| INLINE(static void WhiteToBlack(MarkBit markbit)) {
|
| - DCHECK(IsWhite(markbit));
|
| - markbit.Set();
|
| - markbit.Next().Set();
|
| + DCHECK(mode == MarkBit::ATOMIC || IsWhite(markbit));
|
| + markbit.Set<mode>();
|
| + markbit.Next().Set<mode>();
|
| }
|
|
|
| - INLINE(static void GreyToBlack(MarkBit markbit)) {
|
| - DCHECK(IsGrey(markbit));
|
| - markbit.Next().Set();
|
| + template <MarkBit::AccessMode mode = MarkBit::NON_ATOMIC>
|
| + INLINE(static bool GreyToBlack(MarkBit markbit)) {
|
| + DCHECK(mode == MarkBit::ATOMIC || IsGrey(markbit));
|
| + return markbit.Next().Set<mode>();
|
| }
|
|
|
| enum ObjectColor {
|
|
|