diff options
author | Ian Rogers <irogers@google.com> | 2014-05-20 16:40:37 -0700 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2014-05-20 21:17:03 -0700 |
commit | 3e5cf305db800b2989ad57b7cde8fb3cc9fa1b9e (patch) | |
tree | 52a737323ebd505cf37ca0e4b2dcee6524fba07f | |
parent | 27a2b70f612af9afc0fb5392fb10059f6a0a3569 (diff) | |
download | art-3e5cf305db800b2989ad57b7cde8fb3cc9fa1b9e.zip art-3e5cf305db800b2989ad57b7cde8fb3cc9fa1b9e.tar.gz art-3e5cf305db800b2989ad57b7cde8fb3cc9fa1b9e.tar.bz2 |
Begin migration of art::Atomic to std::atomic.
Change-Id: I4858d9cbed95e5ca560956b9dabd976cebe68333
-rw-r--r-- | compiler/driver/compiler_driver.cc | 4 | ||||
-rw-r--r-- | runtime/atomic.h | 159 | ||||
-rw-r--r-- | runtime/barrier_test.cc | 14 | ||||
-rw-r--r-- | runtime/base/mutex-inl.h | 2 | ||||
-rw-r--r-- | runtime/base/mutex.cc | 43 | ||||
-rw-r--r-- | runtime/base/mutex.h | 4 | ||||
-rw-r--r-- | runtime/gc/accounting/atomic_stack.h | 46 | ||||
-rw-r--r-- | runtime/gc/collector/mark_sweep.cc | 56 | ||||
-rw-r--r-- | runtime/gc/collector/mark_sweep.h | 6 | ||||
-rw-r--r-- | runtime/gc/heap-inl.h | 6 | ||||
-rw-r--r-- | runtime/gc/heap.cc | 36 | ||||
-rw-r--r-- | runtime/gc/heap.h | 4 | ||||
-rw-r--r-- | runtime/gc/space/bump_pointer_space-inl.h | 8 | ||||
-rw-r--r-- | runtime/gc/space/bump_pointer_space.cc | 12 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 2 | ||||
-rw-r--r-- | runtime/gc/space/zygote_space.cc | 2 | ||||
-rw-r--r-- | runtime/gc/space/zygote_space.h | 2 | ||||
-rw-r--r-- | runtime/instrumentation.cc | 8 | ||||
-rw-r--r-- | runtime/mirror/object.cc | 4 | ||||
-rw-r--r-- | runtime/monitor.cc | 6 | ||||
-rw-r--r-- | runtime/monitor.h | 2 | ||||
-rw-r--r-- | runtime/thread_pool_test.cc | 11 |
22 files changed, 282 insertions, 155 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index eb62f1b..999d6a5 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1369,7 +1369,7 @@ class ParallelCompilationManager { self->AssertNoPendingException(); CHECK_GT(work_units, 0U); - index_ = begin; + index_.StoreRelaxed(begin); for (size_t i = 0; i < work_units; ++i) { thread_pool_->AddTask(self, new ForAllClosure(this, end, callback)); } @@ -1384,7 +1384,7 @@ class ParallelCompilationManager { } size_t NextIndex() { - return index_.FetchAndAdd(1); + return index_.FetchAndAddSequentiallyConsistent(1); } private: diff --git a/runtime/atomic.h b/runtime/atomic.h index 1f975dc..9262db6 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -17,7 +17,15 @@ #ifndef ART_RUNTIME_ATOMIC_H_ #define ART_RUNTIME_ATOMIC_H_ +#ifdef __clang__ +#define ART_HAVE_STDATOMIC 1 +#endif + #include <stdint.h> +#if ART_HAVE_STDATOMIC +#include <atomic> +#endif +#include <limits> #include <vector> #include "base/logging.h" @@ -27,6 +35,76 @@ namespace art { class Mutex; +#if ART_HAVE_STDATOMIC +template<typename T> +class Atomic : public std::atomic<T> { + public: + COMPILE_ASSERT(sizeof(T) == sizeof(std::atomic<T>), + std_atomic_size_differs_from_that_of_underlying_type); + COMPILE_ASSERT(alignof(T) == alignof(std::atomic<T>), + std_atomic_alignment_differs_from_that_of_underlying_type); + + Atomic<T>() : std::atomic<T>() { } + + explicit Atomic<T>(T value) : std::atomic<T>(value) { } + + // Load from memory without ordering or synchronization constraints. + T LoadRelaxed() const { + return this->load(std::memory_order_relaxed); + } + + // Load from memory with a total ordering. + T LoadSequentiallyConsistent() const { + return this->load(std::memory_order_seq_cst); + } + + // Store to memory without ordering or synchronization constraints. + void StoreRelaxed(T desired) { + this->store(desired, std::memory_order_relaxed); + } + + // Store to memory with a total ordering. + void StoreSequentiallyConsistent(T desired) { + this->store(desired, std::memory_order_seq_cst); + } + + // Atomically replace the value with desired value if it matches the expected value. Doesn't + // imply ordering or synchronization constraints. + bool CompareExchangeWeakRelaxed(T expected_value, T desired_value) { + return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_relaxed); + } + + // Atomically replace the value with desired value if it matches the expected value. Prior writes + // made to other memory locations by the thread that did the release become visible in this + // thread. + bool CompareExchangeWeakAcquire(T expected_value, T desired_value) { + return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_acquire); + } + + // Atomically replace the value with desired value if it matches the expected value. prior writes + // to other memory locations become visible to the threads that do a consume or an acquire on the + // same location. + bool CompareExchangeWeakRelease(T expected_value, T desired_value) { + return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_release); + } + + T FetchAndAddSequentiallyConsistent(const T value) { + return this->fetch_add(value, std::memory_order_seq_cst); // Return old_value. + } + + T FetchAndSubSequentiallyConsistent(const T value) { + return this->fetch_sub(value, std::memory_order_seq_cst); // Return old value. + } + + volatile T* Address() { + return reinterpret_cast<T*>(this); + } + + static T MaxValue() { + return std::numeric_limits<T>::max(); + } +}; +#else template<typename T> class Atomic { public: @@ -34,24 +112,54 @@ class Atomic { explicit Atomic<T>(T value) : value_(value) { } - Atomic<T>& operator=(T desired) { - Store(desired); - return *this; + // Load from memory without ordering or synchronization constraints. + T LoadRelaxed() const { + return value_; } - T Load() const { - return value_; + // Load from memory with a total ordering. + T LoadSequentiallyConsistent() const; + + // Store to memory without ordering or synchronization constraints. + void StoreRelaxed(T desired) { + value_ = desired; + } + + // Store to memory with a total ordering. + void StoreSequentiallyConsistent(T desired); + + // Atomically replace the value with desired value if it matches the expected value. Doesn't + // imply ordering or synchronization constraints. + bool CompareExchangeWeakRelaxed(T expected_value, T desired_value) { + // TODO: make this relaxed. + return __sync_bool_compare_and_swap(&value_, expected_value, desired_value); } - operator T() const { - return Load(); + // Atomically replace the value with desired value if it matches the expected value. Prior writes + // made to other memory locations by the thread that did the release become visible in this + // thread. + bool CompareExchangeWeakAcquire(T expected_value, T desired_value) { + // TODO: make this acquire. + return __sync_bool_compare_and_swap(&value_, expected_value, desired_value); + } + + // Atomically replace the value with desired value if it matches the expected value. prior writes + // to other memory locations become visible to the threads that do a consume or an acquire on the + // same location. + bool CompareExchangeWeakRelease(T expected_value, T desired_value) { + // TODO: make this release. + return __sync_bool_compare_and_swap(&value_, expected_value, desired_value); + } + + volatile T* Address() { + return &value_; } - T FetchAndAdd(const T value) { + T FetchAndAddSequentiallyConsistent(const T value) { return __sync_fetch_and_add(&value_, value); // Return old_value. } - T FetchAndSub(const T value) { + T FetchAndSubSequentiallyConsistent(const T value) { return __sync_fetch_and_sub(&value_, value); // Return old value. } @@ -71,22 +179,14 @@ class Atomic { return __sync_fetch_and_sub(&value_, 1); // Return old value. } - bool CompareAndSwap(T expected_value, T desired_value) { - return __sync_bool_compare_and_swap(&value_, expected_value, desired_value); - } - - volatile T* Address() { - return &value_; + static T MaxValue() { + return std::numeric_limits<T>::max(); } private: - // Unsafe = operator for non atomic operations on the integer. - void Store(T desired) { - value_ = desired; - } - - volatile T value_; + T value_; }; +#endif typedef Atomic<int32_t> AtomicInteger; @@ -260,6 +360,23 @@ class QuasiAtomic { DISALLOW_COPY_AND_ASSIGN(QuasiAtomic); }; +#if !ART_HAVE_STDATOMIC +template<typename T> +inline T Atomic<T>::LoadSequentiallyConsistent() const { + T result = value_; + QuasiAtomic::MembarLoadLoad(); + return result; +} + +template<typename T> +inline void Atomic<T>::StoreSequentiallyConsistent(T desired) { + QuasiAtomic::MembarStoreStore(); + value_ = desired; + QuasiAtomic::MembarStoreLoad(); +} + +#endif + } // namespace art #endif // ART_RUNTIME_ATOMIC_H_ diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc index 331d0c0..086ef44 100644 --- a/runtime/barrier_test.cc +++ b/runtime/barrier_test.cc @@ -77,20 +77,20 @@ TEST_F(BarrierTest, CheckWait) { barrier.Increment(self, num_threads); // At this point each thread should have passed through the barrier. The first count should be // equal to num_threads. - EXPECT_EQ(num_threads, count1); + EXPECT_EQ(num_threads, count1.LoadRelaxed()); // Count 3 should still be zero since no thread should have gone past the second barrier. - EXPECT_EQ(0, count3); + EXPECT_EQ(0, count3.LoadRelaxed()); // Now lets tell the threads to pass again. barrier.Increment(self, num_threads); // Count 2 should be equal to num_threads since each thread must have passed the second barrier // at this point. - EXPECT_EQ(num_threads, count2); + EXPECT_EQ(num_threads, count2.LoadRelaxed()); // Wait for all the threads to finish. thread_pool.Wait(self, true, false); // All three counts should be equal to num_threads now. - EXPECT_EQ(count1, count2); - EXPECT_EQ(count2, count3); - EXPECT_EQ(num_threads, count3); + EXPECT_EQ(count1.LoadRelaxed(), count2.LoadRelaxed()); + EXPECT_EQ(count2.LoadRelaxed(), count3.LoadRelaxed()); + EXPECT_EQ(num_threads, count3.LoadRelaxed()); } class CheckPassTask : public Task { @@ -133,7 +133,7 @@ TEST_F(BarrierTest, CheckPass) { // Wait for all the tasks to complete using the barrier. barrier.Increment(self, expected_total_tasks); // The total number of completed tasks should be equal to expected_total_tasks. - EXPECT_EQ(count, expected_total_tasks); + EXPECT_EQ(count.LoadRelaxed(), expected_total_tasks); } } // namespace art diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h index a7e25cb..adf4c66 100644 --- a/runtime/base/mutex-inl.h +++ b/runtime/base/mutex-inl.h @@ -221,7 +221,7 @@ inline void ReaderWriterMutex::SharedUnlock(Thread* self) { // Reduce state by 1. done = android_atomic_release_cas(cur_state, cur_state - 1, &state_) == 0; if (done && (cur_state - 1) == 0) { // cas may fail due to noise? - if (num_pending_writers_ > 0 || num_pending_readers_ > 0) { + if (num_pending_writers_.LoadRelaxed() > 0 || num_pending_readers_ > 0) { // Wake any exclusive waiters as there are now no readers. futex(&state_, FUTEX_WAKE, -1, NULL, NULL, 0); } diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index 2bc17bf..6f7f2c1 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -71,12 +71,12 @@ static bool ComputeRelativeTimeSpec(timespec* result_ts, const timespec& lhs, co class ScopedAllMutexesLock { public: explicit ScopedAllMutexesLock(const BaseMutex* mutex) : mutex_(mutex) { - while (!gAllMutexData->all_mutexes_guard.CompareAndSwap(0, mutex)) { + while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakAcquire(0, mutex)) { NanoSleep(100); } } ~ScopedAllMutexesLock() { - while (!gAllMutexData->all_mutexes_guard.CompareAndSwap(mutex_, 0)) { + while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakRelease(mutex_, 0)) { NanoSleep(100); } } @@ -174,34 +174,34 @@ void BaseMutex::RecordContention(uint64_t blocked_tid, uint64_t owner_tid, uint64_t nano_time_blocked) { if (kLogLockContentions) { - ContentionLogData* data = contetion_log_data_; + ContentionLogData* data = contention_log_data_; ++(data->contention_count); data->AddToWaitTime(nano_time_blocked); ContentionLogEntry* log = data->contention_log; // This code is intentionally racy as it is only used for diagnostics. - uint32_t slot = data->cur_content_log_entry; + uint32_t slot = data->cur_content_log_entry.LoadRelaxed(); if (log[slot].blocked_tid == blocked_tid && log[slot].owner_tid == blocked_tid) { ++log[slot].count; } else { uint32_t new_slot; do { - slot = data->cur_content_log_entry; + slot = data->cur_content_log_entry.LoadRelaxed(); new_slot = (slot + 1) % kContentionLogSize; - } while (!data->cur_content_log_entry.CompareAndSwap(slot, new_slot)); + } while (!data->cur_content_log_entry.CompareExchangeWeakRelaxed(slot, new_slot)); log[new_slot].blocked_tid = blocked_tid; log[new_slot].owner_tid = owner_tid; - log[new_slot].count = 1; + log[new_slot].count.StoreRelaxed(1); } } } void BaseMutex::DumpContention(std::ostream& os) const { if (kLogLockContentions) { - const ContentionLogData* data = contetion_log_data_; + const ContentionLogData* data = contention_log_data_; const ContentionLogEntry* log = data->contention_log; uint64_t wait_time = data->wait_time; - uint32_t contention_count = data->contention_count; + uint32_t contention_count = data->contention_count.LoadRelaxed(); if (contention_count == 0) { os << "never contended"; } else { @@ -213,7 +213,7 @@ void BaseMutex::DumpContention(std::ostream& os) const { for (size_t i = 0; i < kContentionLogSize; ++i) { uint64_t blocked_tid = log[i].blocked_tid; uint64_t owner_tid = log[i].owner_tid; - uint32_t count = log[i].count; + uint32_t count = log[i].count.LoadRelaxed(); if (count > 0) { auto it = most_common_blocked.find(blocked_tid); if (it != most_common_blocked.end()) { @@ -261,7 +261,7 @@ Mutex::Mutex(const char* name, LockLevel level, bool recursive) #if ART_USE_FUTEXES state_ = 0; exclusive_owner_ = 0; - num_contenders_ = 0; + DCHECK_EQ(0, num_contenders_.LoadRelaxed()); #elif defined(__BIONIC__) || defined(__APPLE__) // Use recursive mutexes for bionic and Apple otherwise the // non-recursive mutexes don't have TIDs to check lock ownership of. @@ -283,7 +283,8 @@ Mutex::~Mutex() { LOG(shutting_down ? WARNING : FATAL) << "destroying mutex with owner: " << exclusive_owner_; } else { CHECK_EQ(exclusive_owner_, 0U) << "unexpectedly found an owner on unlocked mutex " << name_; - CHECK_EQ(num_contenders_, 0) << "unexpectedly found a contender on mutex " << name_; + CHECK_EQ(num_contenders_.LoadRelaxed(), 0) + << "unexpectedly found a contender on mutex " << name_; } #else // We can't use CHECK_MUTEX_CALL here because on shutdown a suspended daemon thread @@ -406,7 +407,7 @@ void Mutex::ExclusiveUnlock(Thread* self) { done = __sync_bool_compare_and_swap(&state_, cur_state, 0 /* new state */); if (LIKELY(done)) { // Spurious fail? // Wake a contender - if (UNLIKELY(num_contenders_ > 0)) { + if (UNLIKELY(num_contenders_.LoadRelaxed() > 0)) { futex(&state_, FUTEX_WAKE, 1, NULL, NULL, 0); } } @@ -459,7 +460,7 @@ ReaderWriterMutex::~ReaderWriterMutex() { CHECK_EQ(state_, 0); CHECK_EQ(exclusive_owner_, 0U); CHECK_EQ(num_pending_readers_, 0); - CHECK_EQ(num_pending_writers_, 0); + CHECK_EQ(num_pending_writers_.LoadRelaxed(), 0); #else // We can't use CHECK_MUTEX_CALL here because on shutdown a suspended daemon thread // may still be using locks. @@ -523,7 +524,7 @@ void ReaderWriterMutex::ExclusiveUnlock(Thread* self) { done = __sync_bool_compare_and_swap(&state_, -1 /* cur_state*/, 0 /* new state */); if (LIKELY(done)) { // cmpxchg may fail due to noise? // Wake any waiters. - if (UNLIKELY(num_pending_readers_ > 0 || num_pending_writers_ > 0)) { + if (UNLIKELY(num_pending_readers_ > 0 || num_pending_writers_.LoadRelaxed() > 0)) { futex(&state_, FUTEX_WAKE, -1, NULL, NULL, 0); } } @@ -646,7 +647,7 @@ std::ostream& operator<<(std::ostream& os, const ReaderWriterMutex& mu) { ConditionVariable::ConditionVariable(const char* name, Mutex& guard) : name_(name), guard_(guard) { #if ART_USE_FUTEXES - sequence_ = 0; + DCHECK_EQ(0, sequence_.LoadRelaxed()); num_waiters_ = 0; #else pthread_condattr_t cond_attrs; @@ -691,7 +692,7 @@ void ConditionVariable::Broadcast(Thread* self) { sequence_++; // Indicate the broadcast occurred. bool done = false; do { - int32_t cur_sequence = sequence_; + int32_t cur_sequence = sequence_.LoadRelaxed(); // Requeue waiters onto mutex. The waiter holds the contender count on the mutex high ensuring // mutex unlocks will awaken the requeued waiter thread. done = futex(sequence_.Address(), FUTEX_CMP_REQUEUE, 0, @@ -740,7 +741,7 @@ void ConditionVariable::WaitHoldingLocks(Thread* self) { // Ensure the Mutex is contended so that requeued threads are awoken. guard_.num_contenders_++; guard_.recursion_count_ = 1; - int32_t cur_sequence = sequence_; + int32_t cur_sequence = sequence_.LoadRelaxed(); guard_.ExclusiveUnlock(self); if (futex(sequence_.Address(), FUTEX_WAIT, cur_sequence, NULL, NULL, 0) != 0) { // Futex failed, check it is an expected error. @@ -754,7 +755,7 @@ void ConditionVariable::WaitHoldingLocks(Thread* self) { CHECK_GE(num_waiters_, 0); num_waiters_--; // We awoke and so no longer require awakes from the guard_'s unlock. - CHECK_GE(guard_.num_contenders_, 0); + CHECK_GE(guard_.num_contenders_.LoadRelaxed(), 0); guard_.num_contenders_--; #else guard_.recursion_count_ = 0; @@ -775,7 +776,7 @@ void ConditionVariable::TimedWait(Thread* self, int64_t ms, int32_t ns) { // Ensure the Mutex is contended so that requeued threads are awoken. guard_.num_contenders_++; guard_.recursion_count_ = 1; - int32_t cur_sequence = sequence_; + int32_t cur_sequence = sequence_.LoadRelaxed(); guard_.ExclusiveUnlock(self); if (futex(sequence_.Address(), FUTEX_WAIT, cur_sequence, &rel_ts, NULL, 0) != 0) { if (errno == ETIMEDOUT) { @@ -790,7 +791,7 @@ void ConditionVariable::TimedWait(Thread* self, int64_t ms, int32_t ns) { CHECK_GE(num_waiters_, 0); num_waiters_--; // We awoke and so no longer require awakes from the guard_'s unlock. - CHECK_GE(guard_.num_contenders_, 0); + CHECK_GE(guard_.num_contenders_.LoadRelaxed(), 0); guard_.num_contenders_--; #else #if !defined(__APPLE__) diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index 3f35670..e13c8d5 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -160,12 +160,12 @@ class BaseMutex { void AddToWaitTime(uint64_t value); ContentionLogData() : wait_time(0) {} }; - ContentionLogData contetion_log_data_[kContentionLogDataSize]; + ContentionLogData contention_log_data_[kContentionLogDataSize]; public: bool HasEverContended() const { if (kLogLockContentions) { - return contetion_log_data_->contention_count > 0; + return contention_log_data_->contention_count.LoadSequentiallyConsistent() > 0; } return false; } diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h index f3ed8d3..979970c 100644 --- a/runtime/gc/accounting/atomic_stack.h +++ b/runtime/gc/accounting/atomic_stack.h @@ -46,8 +46,8 @@ class AtomicStack { void Reset() { DCHECK(mem_map_.get() != NULL); DCHECK(begin_ != NULL); - front_index_ = 0; - back_index_ = 0; + front_index_.StoreRelaxed(0); + back_index_.StoreRelaxed(0); debug_is_sorted_ = true; int result = madvise(begin_, sizeof(T) * capacity_, MADV_DONTNEED); if (result == -1) { @@ -64,12 +64,12 @@ class AtomicStack { } int32_t index; do { - index = back_index_; + index = back_index_.LoadRelaxed(); if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) { // Stack overflow. return false; } - } while (!back_index_.CompareAndSwap(index, index + 1)); + } while (!back_index_.CompareExchangeWeakRelaxed(index, index + 1)); begin_[index] = value; return true; } @@ -83,13 +83,13 @@ class AtomicStack { int32_t index; int32_t new_index; do { - index = back_index_; + index = back_index_.LoadRelaxed(); new_index = index + num_slots; if (UNLIKELY(static_cast<size_t>(new_index) >= capacity_)) { // Stack overflow. return false; } - } while (!back_index_.CompareAndSwap(index, new_index)); + } while (!back_index_.CompareExchangeWeakRelaxed(index, new_index)); *start_address = &begin_[index]; *end_address = &begin_[new_index]; if (kIsDebugBuild) { @@ -114,31 +114,31 @@ class AtomicStack { if (kIsDebugBuild) { debug_is_sorted_ = false; } - int32_t index = back_index_; + int32_t index = back_index_.LoadRelaxed(); DCHECK_LT(static_cast<size_t>(index), capacity_); - back_index_ = index + 1; + back_index_.StoreRelaxed(index + 1); begin_[index] = value; } T PopBack() { - DCHECK_GT(back_index_, front_index_); + DCHECK_GT(back_index_.LoadRelaxed(), front_index_.LoadRelaxed()); // Decrement the back index non atomically. - back_index_ = back_index_ - 1; - return begin_[back_index_]; + back_index_.StoreRelaxed(back_index_.LoadRelaxed() - 1); + return begin_[back_index_.LoadRelaxed()]; } // Take an item from the front of the stack. T PopFront() { - int32_t index = front_index_; - DCHECK_LT(index, back_index_.Load()); - front_index_ = front_index_ + 1; + int32_t index = front_index_.LoadRelaxed(); + DCHECK_LT(index, back_index_.LoadRelaxed()); + front_index_.StoreRelaxed(index + 1); return begin_[index]; } // Pop a number of elements. void PopBackCount(int32_t n) { DCHECK_GE(Size(), static_cast<size_t>(n)); - back_index_.FetchAndSub(n); + back_index_.FetchAndSubSequentiallyConsistent(n); } bool IsEmpty() const { @@ -146,16 +146,16 @@ class AtomicStack { } size_t Size() const { - DCHECK_LE(front_index_, back_index_); - return back_index_ - front_index_; + DCHECK_LE(front_index_.LoadRelaxed(), back_index_.LoadRelaxed()); + return back_index_.LoadRelaxed() - front_index_.LoadRelaxed(); } T* Begin() const { - return const_cast<T*>(begin_ + front_index_); + return const_cast<T*>(begin_ + front_index_.LoadRelaxed()); } T* End() const { - return const_cast<T*>(begin_ + back_index_); + return const_cast<T*>(begin_ + back_index_.LoadRelaxed()); } size_t Capacity() const { @@ -169,11 +169,11 @@ class AtomicStack { } void Sort() { - int32_t start_back_index = back_index_.Load(); - int32_t start_front_index = front_index_.Load(); + int32_t start_back_index = back_index_.LoadRelaxed(); + int32_t start_front_index = front_index_.LoadRelaxed(); std::sort(Begin(), End()); - CHECK_EQ(start_back_index, back_index_.Load()); - CHECK_EQ(start_front_index, front_index_.Load()); + CHECK_EQ(start_back_index, back_index_.LoadRelaxed()); + CHECK_EQ(start_front_index, front_index_.LoadRelaxed()); if (kIsDebugBuild) { debug_is_sorted_ = true; } diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index cc258f5..43331c3 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -99,9 +99,10 @@ MarkSweep::MarkSweep(Heap* heap, bool is_concurrent, const std::string& name_pre : GarbageCollector(heap, name_prefix + (is_concurrent ? "concurrent mark sweep": "mark sweep")), + current_space_bitmap_(nullptr), mark_bitmap_(nullptr), mark_stack_(nullptr), gc_barrier_(new Barrier(0)), mark_stack_lock_("mark sweep mark stack lock", kMarkSweepMarkStackLock), - is_concurrent_(is_concurrent) { + is_concurrent_(is_concurrent), live_stack_freeze_size_(0) { } void MarkSweep::InitializePhase() { @@ -109,19 +110,19 @@ void MarkSweep::InitializePhase() { mark_stack_ = heap_->GetMarkStack(); DCHECK(mark_stack_ != nullptr); immune_region_.Reset(); - class_count_ = 0; - array_count_ = 0; - other_count_ = 0; - large_object_test_ = 0; - large_object_mark_ = 0; - overhead_time_ = 0; - work_chunks_created_ = 0; - work_chunks_deleted_ = 0; - reference_count_ = 0; - mark_null_count_ = 0; - mark_immune_count_ = 0; - mark_fastpath_count_ = 0; - mark_slowpath_count_ = 0; + class_count_.StoreRelaxed(0); + array_count_.StoreRelaxed(0); + other_count_.StoreRelaxed(0); + large_object_test_.StoreRelaxed(0); + large_object_mark_.StoreRelaxed(0); + overhead_time_ .StoreRelaxed(0); + work_chunks_created_.StoreRelaxed(0); + work_chunks_deleted_.StoreRelaxed(0); + reference_count_.StoreRelaxed(0); + mark_null_count_.StoreRelaxed(0); + mark_immune_count_.StoreRelaxed(0); + mark_fastpath_count_.StoreRelaxed(0); + mark_slowpath_count_.StoreRelaxed(0); { // TODO: I don't think we should need heap bitmap lock to Get the mark bitmap. ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); @@ -596,7 +597,7 @@ class MarkStackTask : public Task { if (kUseFinger) { android_memory_barrier(); if (reinterpret_cast<uintptr_t>(ref) >= - static_cast<uintptr_t>(mark_sweep_->atomic_finger_)) { + static_cast<uintptr_t>(mark_sweep_->atomic_finger_.LoadRelaxed())) { return; } } @@ -881,7 +882,7 @@ void MarkSweep::RecursiveMark() { // This function does not handle heap end increasing, so we must use the space end. uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin()); uintptr_t end = reinterpret_cast<uintptr_t>(space->End()); - atomic_finger_ = static_cast<int32_t>(0xFFFFFFFF); + atomic_finger_.StoreRelaxed(AtomicInteger::MaxValue()); // Create a few worker tasks. const size_t n = thread_count * 2; @@ -1214,7 +1215,9 @@ void MarkSweep::ProcessMarkStackParallel(size_t thread_count) { thread_pool->Wait(self, true, true); thread_pool->StopWorkers(self); mark_stack_->Reset(); - CHECK_EQ(work_chunks_created_, work_chunks_deleted_) << " some of the work chunks were leaked"; + CHECK_EQ(work_chunks_created_.LoadSequentiallyConsistent(), + work_chunks_deleted_.LoadSequentiallyConsistent()) + << " some of the work chunks were leaked"; } // Scan anything that's on the mark stack. @@ -1269,24 +1272,27 @@ inline bool MarkSweep::IsMarked(const Object* object) const void MarkSweep::FinishPhase() { TimingLogger::ScopedSplit split("FinishPhase", &timings_); if (kCountScannedTypes) { - VLOG(gc) << "MarkSweep scanned classes=" << class_count_ << " arrays=" << array_count_ - << " other=" << other_count_; + VLOG(gc) << "MarkSweep scanned classes=" << class_count_.LoadRelaxed() + << " arrays=" << array_count_.LoadRelaxed() << " other=" << other_count_.LoadRelaxed(); } if (kCountTasks) { - VLOG(gc) << "Total number of work chunks allocated: " << work_chunks_created_; + VLOG(gc) << "Total number of work chunks allocated: " << work_chunks_created_.LoadRelaxed(); } if (kMeasureOverhead) { - VLOG(gc) << "Overhead time " << PrettyDuration(overhead_time_); + VLOG(gc) << "Overhead time " << PrettyDuration(overhead_time_.LoadRelaxed()); } if (kProfileLargeObjects) { - VLOG(gc) << "Large objects tested " << large_object_test_ << " marked " << large_object_mark_; + VLOG(gc) << "Large objects tested " << large_object_test_.LoadRelaxed() + << " marked " << large_object_mark_.LoadRelaxed(); } if (kCountJavaLangRefs) { - VLOG(gc) << "References scanned " << reference_count_; + VLOG(gc) << "References scanned " << reference_count_.LoadRelaxed(); } if (kCountMarkedObjects) { - VLOG(gc) << "Marked: null=" << mark_null_count_ << " immune=" << mark_immune_count_ - << " fastpath=" << mark_fastpath_count_ << " slowpath=" << mark_slowpath_count_; + VLOG(gc) << "Marked: null=" << mark_null_count_.LoadRelaxed() + << " immune=" << mark_immune_count_.LoadRelaxed() + << " fastpath=" << mark_fastpath_count_.LoadRelaxed() + << " slowpath=" << mark_slowpath_count_.LoadRelaxed(); } CHECK(mark_stack_->IsEmpty()); // Ensure that the mark stack is empty. mark_stack_->Reset(); diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h index e9a3c3a..d73bf3f 100644 --- a/runtime/gc/collector/mark_sweep.h +++ b/runtime/gc/collector/mark_sweep.h @@ -305,14 +305,14 @@ class MarkSweep : public GarbageCollector { AtomicInteger mark_fastpath_count_; AtomicInteger mark_slowpath_count_; - // Verification. - size_t live_stack_freeze_size_; - std::unique_ptr<Barrier> gc_barrier_; Mutex mark_stack_lock_ ACQUIRED_AFTER(Locks::classlinker_classes_lock_); const bool is_concurrent_; + // Verification. + size_t live_stack_freeze_size_; + private: friend class AddIfReachesAllocSpaceVisitor; // Used by mod-union table. friend class CardScanTask; diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h index 7cee5a0..03b72b6 100644 --- a/runtime/gc/heap-inl.h +++ b/runtime/gc/heap-inl.h @@ -96,7 +96,7 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas CHECK_LE(obj->SizeOf(), usable_size); } const size_t new_num_bytes_allocated = - static_cast<size_t>(num_bytes_allocated_.FetchAndAdd(bytes_allocated)) + bytes_allocated; + static_cast<size_t>(num_bytes_allocated_.FetchAndAddSequentiallyConsistent(bytes_allocated)) + bytes_allocated; // TODO: Deprecate. if (kInstrumented) { if (Runtime::Current()->HasStatsEnabled()) { @@ -264,7 +264,7 @@ inline Heap::AllocationTimer::~AllocationTimer() { // Only if the allocation succeeded, record the time. if (allocated_obj != nullptr) { uint64_t allocation_end_time = NanoTime() / kTimeAdjust; - heap_->total_allocation_time_.FetchAndAdd(allocation_end_time - allocation_start_time_); + heap_->total_allocation_time_.FetchAndAddSequentiallyConsistent(allocation_end_time - allocation_start_time_); } } }; @@ -279,7 +279,7 @@ inline bool Heap::ShouldAllocLargeObject(mirror::Class* c, size_t byte_count) co template <bool kGrow> inline bool Heap::IsOutOfMemoryOnAllocation(AllocatorType allocator_type, size_t alloc_size) { - size_t new_footprint = num_bytes_allocated_ + alloc_size; + size_t new_footprint = num_bytes_allocated_.LoadSequentiallyConsistent() + alloc_size; if (UNLIKELY(new_footprint > max_allowed_footprint_)) { if (UNLIKELY(new_footprint > growth_limit_)) { return true; diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 706d1de..29e8383 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -292,7 +292,7 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max } // TODO: Count objects in the image space here. - num_bytes_allocated_ = 0; + num_bytes_allocated_.StoreRelaxed(0); // Default mark stack size in bytes. static const size_t default_mark_stack_size = 64 * KB; @@ -658,13 +658,13 @@ void Heap::RemoveSpace(space::Space* space) { void Heap::RegisterGCAllocation(size_t bytes) { if (this != nullptr) { - gc_memory_overhead_.FetchAndAdd(bytes); + gc_memory_overhead_.FetchAndAddSequentiallyConsistent(bytes); } } void Heap::RegisterGCDeAllocation(size_t bytes) { if (this != nullptr) { - gc_memory_overhead_.FetchAndSub(bytes); + gc_memory_overhead_.FetchAndSubSequentiallyConsistent(bytes); } } @@ -699,7 +699,8 @@ void Heap::DumpGcPerformanceInfo(std::ostream& os) { } collector->ResetMeasurements(); } - uint64_t allocation_time = static_cast<uint64_t>(total_allocation_time_) * kTimeAdjust; + uint64_t allocation_time = + static_cast<uint64_t>(total_allocation_time_.LoadRelaxed()) * kTimeAdjust; if (total_duration != 0) { const double total_seconds = static_cast<double>(total_duration / 1000) / 1000000.0; os << "Total time spent in GC: " << PrettyDuration(total_duration) << "\n"; @@ -719,7 +720,7 @@ void Heap::DumpGcPerformanceInfo(std::ostream& os) { } os << "Total mutator paused time: " << PrettyDuration(total_paused_time) << "\n"; os << "Total time waiting for GC to complete: " << PrettyDuration(total_wait_time_) << "\n"; - os << "Approximate GC data structures memory overhead: " << gc_memory_overhead_; + os << "Approximate GC data structures memory overhead: " << gc_memory_overhead_.LoadRelaxed(); BaseMutex::DumpAll(os); } @@ -1021,7 +1022,7 @@ void Heap::VerifyObjectBody(mirror::Object* obj) { return; } // Ignore early dawn of the universe verifications. - if (UNLIKELY(static_cast<size_t>(num_bytes_allocated_.Load()) < 10 * KB)) { + if (UNLIKELY(static_cast<size_t>(num_bytes_allocated_.LoadRelaxed()) < 10 * KB)) { return; } CHECK(IsAligned<kObjectAlignment>(obj)) << "Object isn't aligned: " << obj; @@ -1052,9 +1053,9 @@ void Heap::RecordFree(uint64_t freed_objects, int64_t freed_bytes) { // Use signed comparison since freed bytes can be negative when background compaction foreground // transitions occurs. This is caused by the moving objects from a bump pointer space to a // free list backed space typically increasing memory footprint due to padding and binning. - DCHECK_LE(freed_bytes, static_cast<int64_t>(num_bytes_allocated_.Load())); + DCHECK_LE(freed_bytes, static_cast<int64_t>(num_bytes_allocated_.LoadRelaxed())); // Note: This relies on 2s complement for handling negative freed_bytes. - num_bytes_allocated_.FetchAndSub(static_cast<ssize_t>(freed_bytes)); + num_bytes_allocated_.FetchAndSubSequentiallyConsistent(static_cast<ssize_t>(freed_bytes)); if (Runtime::Current()->HasStatsEnabled()) { RuntimeStats* thread_stats = Thread::Current()->GetStats(); thread_stats->freed_objects += freed_objects; @@ -1312,7 +1313,7 @@ void Heap::TransitionCollector(CollectorType collector_type) { VLOG(heap) << "TransitionCollector: " << static_cast<int>(collector_type_) << " -> " << static_cast<int>(collector_type); uint64_t start_time = NanoTime(); - uint32_t before_allocated = num_bytes_allocated_.Load(); + uint32_t before_allocated = num_bytes_allocated_.LoadSequentiallyConsistent(); ThreadList* tl = Runtime::Current()->GetThreadList(); Thread* self = Thread::Current(); ScopedThreadStateChange tsc(self, kWaitingPerformingGc); @@ -1390,7 +1391,7 @@ void Heap::TransitionCollector(CollectorType collector_type) { uint64_t duration = NanoTime() - start_time; GrowForUtilization(semi_space_collector_); FinishGC(self, collector::kGcTypeFull); - int32_t after_allocated = num_bytes_allocated_.Load(); + int32_t after_allocated = num_bytes_allocated_.LoadSequentiallyConsistent(); int32_t delta_allocated = before_allocated - after_allocated; LOG(INFO) << "Heap transition to " << process_state_ << " took " << PrettyDuration(duration) << " saved at least " << PrettySize(delta_allocated); @@ -2421,7 +2422,7 @@ bool Heap::IsMovableObject(const mirror::Object* obj) const { } void Heap::UpdateMaxNativeFootprint() { - size_t native_size = native_bytes_allocated_; + size_t native_size = native_bytes_allocated_.LoadRelaxed(); // TODO: Tune the native heap utilization to be a value other than the java heap utilization. size_t target_size = native_size / GetTargetHeapUtilization(); if (target_size > native_size + max_free_) { @@ -2693,21 +2694,22 @@ void Heap::RegisterNativeAllocation(JNIEnv* env, int bytes) { native_need_to_run_finalization_ = false; } // Total number of native bytes allocated. - native_bytes_allocated_.FetchAndAdd(bytes); - if (static_cast<size_t>(native_bytes_allocated_) > native_footprint_gc_watermark_) { + size_t new_native_bytes_allocated = native_bytes_allocated_.FetchAndAddSequentiallyConsistent(bytes); + new_native_bytes_allocated += bytes; + if (new_native_bytes_allocated > native_footprint_gc_watermark_) { collector::GcType gc_type = have_zygote_space_ ? collector::kGcTypePartial : collector::kGcTypeFull; // The second watermark is higher than the gc watermark. If you hit this it means you are // allocating native objects faster than the GC can keep up with. - if (static_cast<size_t>(native_bytes_allocated_) > native_footprint_limit_) { + if (new_native_bytes_allocated > native_footprint_limit_) { if (WaitForGcToComplete(kGcCauseForNativeAlloc, self) != collector::kGcTypeNone) { // Just finished a GC, attempt to run finalizers. RunFinalization(env); CHECK(!env->ExceptionCheck()); } // If we still are over the watermark, attempt a GC for alloc and run finalizers. - if (static_cast<size_t>(native_bytes_allocated_) > native_footprint_limit_) { + if (new_native_bytes_allocated > native_footprint_limit_) { CollectGarbageInternal(gc_type, kGcCauseForNativeAlloc, false); RunFinalization(env); native_need_to_run_finalization_ = false; @@ -2729,7 +2731,7 @@ void Heap::RegisterNativeAllocation(JNIEnv* env, int bytes) { void Heap::RegisterNativeFree(JNIEnv* env, int bytes) { int expected_size, new_size; do { - expected_size = native_bytes_allocated_.Load(); + expected_size = native_bytes_allocated_.LoadRelaxed(); new_size = expected_size - bytes; if (UNLIKELY(new_size < 0)) { ScopedObjectAccess soa(env); @@ -2738,7 +2740,7 @@ void Heap::RegisterNativeFree(JNIEnv* env, int bytes) { "registered as allocated", bytes, expected_size).c_str()); break; } - } while (!native_bytes_allocated_.CompareAndSwap(expected_size, new_size)); + } while (!native_bytes_allocated_.CompareExchangeWeakRelaxed(expected_size, new_size)); } size_t Heap::GetTotalMemory() const { diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index eea2879..46d1268 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -373,7 +373,7 @@ class Heap { // Returns the number of bytes currently allocated. size_t GetBytesAllocated() const { - return num_bytes_allocated_; + return num_bytes_allocated_.LoadSequentiallyConsistent(); } // Returns the number of objects currently allocated. @@ -409,7 +409,7 @@ class Heap { // Implements java.lang.Runtime.freeMemory. size_t GetFreeMemory() const { - return GetTotalMemory() - num_bytes_allocated_; + return GetTotalMemory() - num_bytes_allocated_.LoadSequentiallyConsistent(); } // get the space that corresponds to an object's address. Current implementation searches all diff --git a/runtime/gc/space/bump_pointer_space-inl.h b/runtime/gc/space/bump_pointer_space-inl.h index 497a61f..71c295e 100644 --- a/runtime/gc/space/bump_pointer_space-inl.h +++ b/runtime/gc/space/bump_pointer_space-inl.h @@ -48,8 +48,8 @@ inline mirror::Object* BumpPointerSpace::AllocThreadUnsafe(Thread* self, size_t end_ += num_bytes; *bytes_allocated = num_bytes; // Use the CAS free versions as an optimization. - objects_allocated_ = objects_allocated_ + 1; - bytes_allocated_ = bytes_allocated_ + num_bytes; + objects_allocated_.StoreRelaxed(objects_allocated_.LoadRelaxed() + 1); + bytes_allocated_.StoreRelaxed(bytes_allocated_.LoadRelaxed() + num_bytes); if (UNLIKELY(usable_size != nullptr)) { *usable_size = num_bytes; } @@ -76,8 +76,8 @@ inline mirror::Object* BumpPointerSpace::AllocNonvirtualWithoutAccounting(size_t inline mirror::Object* BumpPointerSpace::AllocNonvirtual(size_t num_bytes) { mirror::Object* ret = AllocNonvirtualWithoutAccounting(num_bytes); if (ret != nullptr) { - objects_allocated_.FetchAndAdd(1); - bytes_allocated_.FetchAndAdd(num_bytes); + objects_allocated_.FetchAndAddSequentiallyConsistent(1); + bytes_allocated_.FetchAndAddSequentiallyConsistent(num_bytes); } return ret; } diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc index fcd772b..fd0a92d 100644 --- a/runtime/gc/space/bump_pointer_space.cc +++ b/runtime/gc/space/bump_pointer_space.cc @@ -68,8 +68,8 @@ void BumpPointerSpace::Clear() { // Reset the end of the space back to the beginning, we move the end forward as we allocate // objects. SetEnd(Begin()); - objects_allocated_ = 0; - bytes_allocated_ = 0; + objects_allocated_.StoreRelaxed(0); + bytes_allocated_.StoreRelaxed(0); growth_end_ = Limit(); { MutexLock mu(Thread::Current(), block_lock_); @@ -204,7 +204,7 @@ accounting::ContinuousSpaceBitmap::SweepCallback* BumpPointerSpace::GetSweepCall uint64_t BumpPointerSpace::GetBytesAllocated() { // Start out pre-determined amount (blocks which are not being allocated into). - uint64_t total = static_cast<uint64_t>(bytes_allocated_.Load()); + uint64_t total = static_cast<uint64_t>(bytes_allocated_.LoadRelaxed()); Thread* self = Thread::Current(); MutexLock mu(self, *Locks::runtime_shutdown_lock_); MutexLock mu2(self, *Locks::thread_list_lock_); @@ -222,7 +222,7 @@ uint64_t BumpPointerSpace::GetBytesAllocated() { uint64_t BumpPointerSpace::GetObjectsAllocated() { // Start out pre-determined amount (blocks which are not being allocated into). - uint64_t total = static_cast<uint64_t>(objects_allocated_.Load()); + uint64_t total = static_cast<uint64_t>(objects_allocated_.LoadRelaxed()); Thread* self = Thread::Current(); MutexLock mu(self, *Locks::runtime_shutdown_lock_); MutexLock mu2(self, *Locks::thread_list_lock_); @@ -239,8 +239,8 @@ uint64_t BumpPointerSpace::GetObjectsAllocated() { } void BumpPointerSpace::RevokeThreadLocalBuffersLocked(Thread* thread) { - objects_allocated_.FetchAndAdd(thread->GetThreadLocalObjectsAllocated()); - bytes_allocated_.FetchAndAdd(thread->GetThreadLocalBytesAllocated()); + objects_allocated_.FetchAndAddSequentiallyConsistent(thread->GetThreadLocalObjectsAllocated()); + bytes_allocated_.FetchAndAddSequentiallyConsistent(thread->GetThreadLocalBytesAllocated()); thread->SetTlab(nullptr, nullptr); } diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 5036095..335df69 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -239,7 +239,7 @@ ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_locat *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str()); return nullptr; } - uint32_t bitmap_index = bitmap_index_.FetchAndAdd(1); + uint32_t bitmap_index = bitmap_index_.FetchAndAddSequentiallyConsistent(1); std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_filename, bitmap_index)); std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap( diff --git a/runtime/gc/space/zygote_space.cc b/runtime/gc/space/zygote_space.cc index 0466413..fb3a12e 100644 --- a/runtime/gc/space/zygote_space.cc +++ b/runtime/gc/space/zygote_space.cc @@ -115,7 +115,7 @@ void ZygoteSpace::SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* ar // Need to mark the card since this will update the mod-union table next GC cycle. card_table->MarkCard(ptrs[i]); } - zygote_space->objects_allocated_.FetchAndSub(num_ptrs); + zygote_space->objects_allocated_.FetchAndSubSequentiallyConsistent(num_ptrs); } } // namespace space diff --git a/runtime/gc/space/zygote_space.h b/runtime/gc/space/zygote_space.h index 50fc62b..5d5fe76 100644 --- a/runtime/gc/space/zygote_space.h +++ b/runtime/gc/space/zygote_space.h @@ -65,7 +65,7 @@ class ZygoteSpace FINAL : public ContinuousMemMapAllocSpace { } uint64_t GetObjectsAllocated() { - return objects_allocated_; + return objects_allocated_.LoadSequentiallyConsistent(); } void Clear() OVERRIDE; diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 075d225..2dbcc80 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -522,9 +522,9 @@ void Instrumentation::SetEntrypointsInstrumented(bool instrumented) { void Instrumentation::InstrumentQuickAllocEntryPoints() { // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code // should be guarded by a lock. - DCHECK_GE(quick_alloc_entry_points_instrumentation_counter_.Load(), 0); + DCHECK_GE(quick_alloc_entry_points_instrumentation_counter_.LoadSequentiallyConsistent(), 0); const bool enable_instrumentation = - quick_alloc_entry_points_instrumentation_counter_.FetchAndAdd(1) == 0; + quick_alloc_entry_points_instrumentation_counter_.FetchAndAddSequentiallyConsistent(1) == 0; if (enable_instrumentation) { SetEntrypointsInstrumented(true); } @@ -533,9 +533,9 @@ void Instrumentation::InstrumentQuickAllocEntryPoints() { void Instrumentation::UninstrumentQuickAllocEntryPoints() { // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code // should be guarded by a lock. - DCHECK_GT(quick_alloc_entry_points_instrumentation_counter_.Load(), 0); + DCHECK_GT(quick_alloc_entry_points_instrumentation_counter_.LoadSequentiallyConsistent(), 0); const bool disable_instrumentation = - quick_alloc_entry_points_instrumentation_counter_.FetchAndSub(1) == 1; + quick_alloc_entry_points_instrumentation_counter_.FetchAndSubSequentiallyConsistent(1) == 1; if (disable_instrumentation) { SetEntrypointsInstrumented(false); } diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index 04905a5..69e5a84 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -139,10 +139,10 @@ int32_t Object::GenerateIdentityHashCode() { static AtomicInteger seed(987654321 + std::time(nullptr)); int32_t expected_value, new_value; do { - expected_value = static_cast<uint32_t>(seed.Load()); + expected_value = static_cast<uint32_t>(seed.LoadRelaxed()); new_value = expected_value * 1103515245 + 12345; } while ((expected_value & LockWord::kHashMask) == 0 || - !seed.CompareAndSwap(expected_value, new_value)); + !seed.CompareExchangeWeakRelaxed(expected_value, new_value)); return expected_value & LockWord::kHashMask; } diff --git a/runtime/monitor.cc b/runtime/monitor.cc index 0beb651..f783edb 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -99,12 +99,12 @@ Monitor::Monitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_ int32_t Monitor::GetHashCode() { while (!HasHashCode()) { - if (hash_code_.CompareAndSwap(0, mirror::Object::GenerateIdentityHashCode())) { + if (hash_code_.CompareExchangeWeakRelaxed(0, mirror::Object::GenerateIdentityHashCode())) { break; } } DCHECK(HasHashCode()); - return hash_code_.Load(); + return hash_code_.LoadRelaxed(); } bool Monitor::Install(Thread* self) { @@ -119,7 +119,7 @@ bool Monitor::Install(Thread* self) { break; } case LockWord::kHashCode: { - CHECK_EQ(hash_code_, static_cast<int32_t>(lw.GetHashCode())); + CHECK_EQ(hash_code_.LoadRelaxed(), static_cast<int32_t>(lw.GetHashCode())); break; } case LockWord::kFatLocked: { diff --git a/runtime/monitor.h b/runtime/monitor.h index bc5d2e4..bc1b2ed4 100644 --- a/runtime/monitor.h +++ b/runtime/monitor.h @@ -107,7 +107,7 @@ class Monitor { bool IsLocked() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool HasHashCode() const { - return hash_code_.Load() != 0; + return hash_code_.LoadRelaxed() != 0; } MonitorId GetMonitorId() const { diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc index c1a1ad7..292c94f 100644 --- a/runtime/thread_pool_test.cc +++ b/runtime/thread_pool_test.cc @@ -69,7 +69,7 @@ TEST_F(ThreadPoolTest, CheckRun) { // Wait for tasks to complete. thread_pool.Wait(self, true, false); // Make sure that we finished all the work. - EXPECT_EQ(num_tasks, count); + EXPECT_EQ(num_tasks, count.LoadSequentiallyConsistent()); } TEST_F(ThreadPoolTest, StopStart) { @@ -82,7 +82,7 @@ TEST_F(ThreadPoolTest, StopStart) { } usleep(200); // Check that no threads started prematurely. - EXPECT_EQ(0, count); + EXPECT_EQ(0, count.LoadSequentiallyConsistent()); // Signal the threads to start processing tasks. thread_pool.StartWorkers(self); usleep(200); @@ -91,10 +91,11 @@ TEST_F(ThreadPoolTest, StopStart) { thread_pool.AddTask(self, new CountTask(&bad_count)); usleep(200); // Ensure that the task added after the workers were stopped doesn't get run. - EXPECT_EQ(0, bad_count); + EXPECT_EQ(0, bad_count.LoadSequentiallyConsistent()); // Allow tasks to finish up and delete themselves. thread_pool.StartWorkers(self); - while (count.Load() != num_tasks && bad_count.Load() != 1) { + while (count.LoadSequentiallyConsistent() != num_tasks && + bad_count.LoadSequentiallyConsistent() != 1) { usleep(200); } thread_pool.StopWorkers(self); @@ -135,7 +136,7 @@ TEST_F(ThreadPoolTest, RecursiveTest) { thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth)); thread_pool.StartWorkers(self); thread_pool.Wait(self, true, false); - EXPECT_EQ((1 << depth) - 1, count); + EXPECT_EQ((1 << depth) - 1, count.LoadSequentiallyConsistent()); } } // namespace art |