blob: 04daea85b1921ca9273c10843d62175c76cc7816 [file] [log] [blame]
Elliott Hughes5ea047b2011-09-13 14:38:18 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Brian Carlstromfc0e3212013-07-17 14:40:12 -070017#ifndef ART_RUNTIME_ATOMIC_H_
18#define ART_RUNTIME_ATOMIC_H_
Elliott Hughes5ea047b2011-09-13 14:38:18 -070019
Ian Rogers3e5cf302014-05-20 16:40:37 -070020#ifdef __clang__
21#define ART_HAVE_STDATOMIC 1
22#endif
23
Elliott Hughes7c6169d2012-05-02 16:11:48 -070024#include <stdint.h>
Ian Rogers3e5cf302014-05-20 16:40:37 -070025#if ART_HAVE_STDATOMIC
26#include <atomic>
27#endif
28#include <limits>
Ian Rogersb122a4b2013-11-19 18:00:50 -080029#include <vector>
Elliott Hughes7c6169d2012-05-02 16:11:48 -070030
Ian Rogersa9844542014-04-21 17:01:02 -070031#include "base/logging.h"
Elliott Hughes76160052012-12-12 16:31:20 -080032#include "base/macros.h"
Elliott Hughes5ea047b2011-09-13 14:38:18 -070033
34namespace art {
35
Ian Rogersb122a4b2013-11-19 18:00:50 -080036class Mutex;
37
Hans Boehm30359612014-05-21 17:46:23 -070038// QuasiAtomic encapsulates two separate facilities that we are
39// trying to move away from: "quasiatomic" 64 bit operations
40// and custom memory fences. For the time being, they remain
41// exposed. Clients should be converted to use either class Atomic
42// below whenever possible, and should eventually use C++11 atomics.
43// The two facilities that do not have a good C++11 analog are
44// ThreadFenceForConstructor and Atomic::*JavaData.
45//
Elliott Hughes7c6169d2012-05-02 16:11:48 -070046// NOTE: Two "quasiatomic" operations on the exact same memory address
47// are guaranteed to operate atomically with respect to each other,
48// but no guarantees are made about quasiatomic operations mixed with
49// non-quasiatomic operations on the same address, nor about
50// quasiatomic operations that are performed on partially-overlapping
51// memory.
Elliott Hughes7c6169d2012-05-02 16:11:48 -070052class QuasiAtomic {
Ian Rogers936b37f2014-02-14 00:52:24 -080053#if defined(__mips__) && !defined(__LP64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -080054 static constexpr bool kNeedSwapMutexes = true;
55#else
56 static constexpr bool kNeedSwapMutexes = false;
57#endif
58
Elliott Hughes7c6169d2012-05-02 16:11:48 -070059 public:
60 static void Startup();
Elliott Hughes5ea047b2011-09-13 14:38:18 -070061
Elliott Hughes7c6169d2012-05-02 16:11:48 -070062 static void Shutdown();
Elliott Hughes5ea047b2011-09-13 14:38:18 -070063
Ian Rogers9adbff52013-01-23 18:19:03 -080064 // Reads the 64-bit value at "addr" without tearing.
Ian Rogersb122a4b2013-11-19 18:00:50 -080065 static int64_t Read64(volatile const int64_t* addr) {
66 if (!kNeedSwapMutexes) {
Ian Rogersa9844542014-04-21 17:01:02 -070067 int64_t value;
68#if defined(__LP64__)
69 value = *addr;
70#else
71#if defined(__arm__)
72#if defined(__ARM_FEATURE_LPAE)
73 // With LPAE support (such as Cortex-A15) then ldrd is defined not to tear.
74 __asm__ __volatile__("@ QuasiAtomic::Read64\n"
75 "ldrd %0, %H0, %1"
76 : "=r" (value)
77 : "m" (*addr));
78#else
79 // Exclusive loads are defined not to tear, clearing the exclusive state isn't necessary.
80 __asm__ __volatile__("@ QuasiAtomic::Read64\n"
81 "ldrexd %0, %H0, %1"
82 : "=r" (value)
83 : "Q" (*addr));
84#endif
85#elif defined(__i386__)
86 __asm__ __volatile__(
87 "movq %1, %0\n"
88 : "=x" (value)
89 : "m" (*addr));
90#else
91 LOG(FATAL) << "Unsupported architecture";
92#endif
93#endif // defined(__LP64__)
94 return value;
Ian Rogersb122a4b2013-11-19 18:00:50 -080095 } else {
96 return SwapMutexRead64(addr);
97 }
98 }
Elliott Hughes7c6169d2012-05-02 16:11:48 -070099
Ian Rogers9adbff52013-01-23 18:19:03 -0800100 // Writes to the 64-bit value at "addr" without tearing.
Ian Rogersa9844542014-04-21 17:01:02 -0700101 static void Write64(volatile int64_t* addr, int64_t value) {
Ian Rogersb122a4b2013-11-19 18:00:50 -0800102 if (!kNeedSwapMutexes) {
Ian Rogersa9844542014-04-21 17:01:02 -0700103#if defined(__LP64__)
104 *addr = value;
105#else
106#if defined(__arm__)
107#if defined(__ARM_FEATURE_LPAE)
108 // If we know that ARM architecture has LPAE (such as Cortex-A15) strd is defined not to tear.
109 __asm__ __volatile__("@ QuasiAtomic::Write64\n"
110 "strd %1, %H1, %0"
111 : "=m"(*addr)
112 : "r" (value));
113#else
114 // The write is done as a swap so that the cache-line is in the exclusive state for the store.
115 int64_t prev;
116 int status;
117 do {
118 __asm__ __volatile__("@ QuasiAtomic::Write64\n"
119 "ldrexd %0, %H0, %2\n"
120 "strexd %1, %3, %H3, %2"
121 : "=&r" (prev), "=&r" (status), "+Q"(*addr)
122 : "r" (value)
123 : "cc");
124 } while (UNLIKELY(status != 0));
125#endif
126#elif defined(__i386__)
127 __asm__ __volatile__(
128 "movq %1, %0"
129 : "=m" (*addr)
130 : "x" (value));
131#else
132 LOG(FATAL) << "Unsupported architecture";
133#endif
134#endif // defined(__LP64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -0800135 } else {
Ian Rogersa9844542014-04-21 17:01:02 -0700136 SwapMutexWrite64(addr, value);
Ian Rogersb122a4b2013-11-19 18:00:50 -0800137 }
138 }
Ian Rogers9adbff52013-01-23 18:19:03 -0800139
140 // Atomically compare the value at "addr" to "old_value", if equal replace it with "new_value"
141 // and return true. Otherwise, don't swap, and return false.
Hans Boehm30359612014-05-21 17:46:23 -0700142 // This is fully ordered, i.e. it has C++11 memory_order_seq_cst
143 // semantics (assuming all other accesses use a mutex if this one does).
144 // This has "strong" semantics; if it fails then it is guaranteed that
145 // at some point during the execution of Cas64, *addr was not equal to
146 // old_value.
Ian Rogersb122a4b2013-11-19 18:00:50 -0800147 static bool Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
148 if (!kNeedSwapMutexes) {
149 return __sync_bool_compare_and_swap(addr, old_value, new_value);
150 } else {
151 return SwapMutexCas64(old_value, new_value, addr);
152 }
153 }
Ian Rogers9adbff52013-01-23 18:19:03 -0800154
155 // Does the architecture provide reasonable atomic long operations or do we fall back on mutexes?
Ian Rogersb122a4b2013-11-19 18:00:50 -0800156 static bool LongAtomicsUseMutexes() {
Ian Rogers63c5dd02014-05-19 22:55:00 -0700157 return kNeedSwapMutexes;
Ian Rogersb122a4b2013-11-19 18:00:50 -0800158 }
159
Hans Boehm30359612014-05-21 17:46:23 -0700160 #if ART_HAVE_STDATOMIC
161
Hans Boehma1ec0652014-06-06 17:13:03 -0700162 static void ThreadFenceAcquire() {
Hans Boehm30359612014-05-21 17:46:23 -0700163 std::atomic_thread_fence(std::memory_order_acquire);
164 }
165
Hans Boehma1ec0652014-06-06 17:13:03 -0700166 static void ThreadFenceRelease() {
Hans Boehm30359612014-05-21 17:46:23 -0700167 std::atomic_thread_fence(std::memory_order_release);
168 }
169
170 static void ThreadFenceForConstructor() {
171 #if defined(__aarch64__)
172 __asm__ __volatile__("dmb ishst" : : : "memory");
173 #else
174 std::atomic_thread_fence(std::memory_order_release);
175 #endif
176 }
177
178 static void ThreadFenceSequentiallyConsistent() {
179 std::atomic_thread_fence(std::memory_order_seq_cst);
180 }
181
182 #else
183
184 static void ThreadFenceAcquire() {
Stuart Monteith5817e892014-02-18 11:16:29 +0000185 #if defined(__arm__) || defined(__aarch64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -0800186 __asm__ __volatile__("dmb ish" : : : "memory");
Hans Boehm30359612014-05-21 17:46:23 -0700187 // Could possibly use dmb ishld on aarch64
188 // But currently we also use this on volatile loads
189 // to enforce store atomicity. Ishld is
190 // insufficient for that purpose.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800191 #elif defined(__i386__) || defined(__x86_64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -0800192 __asm__ __volatile__("" : : : "memory");
193 #elif defined(__mips__)
194 __asm__ __volatile__("sync" : : : "memory");
195 #else
196 #error Unexpected architecture
197 #endif
198 }
199
Hans Boehm30359612014-05-21 17:46:23 -0700200 static void ThreadFenceRelease() {
Stuart Monteith5817e892014-02-18 11:16:29 +0000201 #if defined(__arm__) || defined(__aarch64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -0800202 __asm__ __volatile__("dmb ish" : : : "memory");
Hans Boehm30359612014-05-21 17:46:23 -0700203 // ishst doesn't order load followed by store.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800204 #elif defined(__i386__) || defined(__x86_64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -0800205 __asm__ __volatile__("" : : : "memory");
206 #elif defined(__mips__)
207 __asm__ __volatile__("sync" : : : "memory");
208 #else
209 #error Unexpected architecture
210 #endif
211 }
212
Hans Boehm30359612014-05-21 17:46:23 -0700213 // Fence at the end of a constructor with final fields
214 // or allocation. We believe this
215 // only has to order stores, and can thus be weaker than
216 // release on aarch64.
217 static void ThreadFenceForConstructor() {
Stuart Monteith5817e892014-02-18 11:16:29 +0000218 #if defined(__arm__) || defined(__aarch64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -0800219 __asm__ __volatile__("dmb ishst" : : : "memory");
Ian Rogersef7d42f2014-01-06 12:55:46 -0800220 #elif defined(__i386__) || defined(__x86_64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -0800221 __asm__ __volatile__("" : : : "memory");
222 #elif defined(__mips__)
223 __asm__ __volatile__("sync" : : : "memory");
224 #else
225 #error Unexpected architecture
226 #endif
227 }
228
Hans Boehm30359612014-05-21 17:46:23 -0700229 static void ThreadFenceSequentiallyConsistent() {
Stuart Monteith5817e892014-02-18 11:16:29 +0000230 #if defined(__arm__) || defined(__aarch64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -0800231 __asm__ __volatile__("dmb ish" : : : "memory");
Ian Rogersef7d42f2014-01-06 12:55:46 -0800232 #elif defined(__i386__) || defined(__x86_64__)
Ian Rogersb122a4b2013-11-19 18:00:50 -0800233 __asm__ __volatile__("mfence" : : : "memory");
234 #elif defined(__mips__)
235 __asm__ __volatile__("sync" : : : "memory");
236 #else
237 #error Unexpected architecture
238 #endif
239 }
Hans Boehm30359612014-05-21 17:46:23 -0700240 #endif
Elliott Hughes7c6169d2012-05-02 16:11:48 -0700241
242 private:
Ian Rogersb122a4b2013-11-19 18:00:50 -0800243 static Mutex* GetSwapMutex(const volatile int64_t* addr);
244 static int64_t SwapMutexRead64(volatile const int64_t* addr);
245 static void SwapMutexWrite64(volatile int64_t* addr, int64_t val);
246 static bool SwapMutexCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr);
247
248 // We stripe across a bunch of different mutexes to reduce contention.
249 static constexpr size_t kSwapMutexCount = 32;
250 static std::vector<Mutex*>* gSwapMutexes;
251
Elliott Hughes7c6169d2012-05-02 16:11:48 -0700252 DISALLOW_COPY_AND_ASSIGN(QuasiAtomic);
253};
Elliott Hughes5ea047b2011-09-13 14:38:18 -0700254
Hans Boehm30359612014-05-21 17:46:23 -0700255#if ART_HAVE_STDATOMIC
256template<typename T>
257class Atomic : public std::atomic<T> {
258 public:
259 Atomic<T>() : std::atomic<T>() { }
260
261 explicit Atomic<T>(T value) : std::atomic<T>(value) { }
262
263 // Load from memory without ordering or synchronization constraints.
264 T LoadRelaxed() const {
265 return this->load(std::memory_order_relaxed);
266 }
267
268 // Word tearing allowed, but may race.
269 // TODO: Optimize?
270 // There has been some discussion of eventually disallowing word
271 // tearing for Java data loads.
272 T LoadJavaData() const {
273 return this->load(std::memory_order_relaxed);
274 }
275
276 // Load from memory with a total ordering.
277 // Corresponds exactly to a Java volatile load.
278 T LoadSequentiallyConsistent() const {
279 return this->load(std::memory_order_seq_cst);
280 }
281
282 // Store to memory without ordering or synchronization constraints.
283 void StoreRelaxed(T desired) {
284 this->store(desired, std::memory_order_relaxed);
285 }
286
287 // Word tearing allowed, but may race.
288 void StoreJavaData(T desired) {
289 this->store(desired, std::memory_order_relaxed);
290 }
291
292 // Store to memory with release ordering.
293 void StoreRelease(T desired) {
294 this->store(desired, std::memory_order_release);
295 }
296
297 // Store to memory with a total ordering.
298 void StoreSequentiallyConsistent(T desired) {
299 this->store(desired, std::memory_order_seq_cst);
300 }
301
302 // Atomically replace the value with desired value if it matches the expected value.
303 // Participates in total ordering of atomic operations.
304 bool CompareExchangeStrongSequentiallyConsistent(T expected_value, T desired_value) {
305 return this->compare_exchange_strong(expected_value, desired_value, std::memory_order_seq_cst);
306 }
307
308 // The same, except it may fail spuriously.
309 bool CompareExchangeWeakSequentiallyConsistent(T expected_value, T desired_value) {
310 return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_seq_cst);
311 }
312
313 // Atomically replace the value with desired value if it matches the expected value. Doesn't
314 // imply ordering or synchronization constraints.
315 bool CompareExchangeStrongRelaxed(T expected_value, T desired_value) {
316 return this->compare_exchange_strong(expected_value, desired_value, std::memory_order_relaxed);
317 }
318
319 // The same, except it may fail spuriously.
320 bool CompareExchangeWeakRelaxed(T expected_value, T desired_value) {
321 return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_relaxed);
322 }
323
324 // Atomically replace the value with desired value if it matches the expected value. Prior writes
325 // made to other memory locations by the thread that did the release become visible in this
326 // thread.
327 bool CompareExchangeWeakAcquire(T expected_value, T desired_value) {
328 return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_acquire);
329 }
330
331 // Atomically replace the value with desired value if it matches the expected value. prior writes
332 // to other memory locations become visible to the threads that do a consume or an acquire on the
333 // same location.
334 bool CompareExchangeWeakRelease(T expected_value, T desired_value) {
335 return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_release);
336 }
337
338 T FetchAndAddSequentiallyConsistent(const T value) {
339 return this->fetch_add(value, std::memory_order_seq_cst); // Return old_value.
340 }
341
342 T FetchAndSubSequentiallyConsistent(const T value) {
343 return this->fetch_sub(value, std::memory_order_seq_cst); // Return old value.
344 }
345
346 volatile T* Address() {
347 return reinterpret_cast<T*>(this);
348 }
349
350 static T MaxValue() {
351 return std::numeric_limits<T>::max();
352 }
Hans Boehm30359612014-05-21 17:46:23 -0700353};
354
355#else
356
357template<typename T> class Atomic;
358
359// Helper class for Atomic to deal separately with size 8 and small
360// objects. Should not be used directly.
361
362template<int SZ, class T> struct AtomicHelper {
363 friend class Atomic<T>;
364
Hans Boehma1ec0652014-06-06 17:13:03 -0700365 private:
Hans Boehm30359612014-05-21 17:46:23 -0700366 COMPILE_ASSERT(sizeof(T) <= 4, bad_atomic_helper_arg);
367
368 static T LoadRelaxed(const volatile T* loc) {
369 // sizeof(T) <= 4
370 return *loc;
371 }
372
373 static void StoreRelaxed(volatile T* loc, T desired) {
374 // sizeof(T) <= 4
375 *loc = desired;
376 }
377
378 static bool CompareExchangeStrongSequentiallyConsistent(volatile T* loc,
379 T expected_value, T desired_value) {
380 // sizeof(T) <= 4
381 return __sync_bool_compare_and_swap(loc, expected_value, desired_value);
382 }
383};
384
385template<class T> struct AtomicHelper<8, T> {
386 friend class Atomic<T>;
387
Hans Boehma1ec0652014-06-06 17:13:03 -0700388 private:
Hans Boehm30359612014-05-21 17:46:23 -0700389 COMPILE_ASSERT(sizeof(T) == 8, bad_large_atomic_helper_arg);
390
391 static T LoadRelaxed(const volatile T* loc) {
392 // sizeof(T) == 8
393 volatile const int64_t* loc_ptr =
394 reinterpret_cast<volatile const int64_t*>(loc);
395 return reinterpret_cast<T>(QuasiAtomic::Read64(loc_ptr));
396 }
397
398 static void StoreRelaxed(volatile T* loc, T desired) {
399 // sizeof(T) == 8
400 volatile int64_t* loc_ptr =
401 reinterpret_cast<volatile int64_t*>(loc);
402 QuasiAtomic::Write64(loc_ptr,
403 reinterpret_cast<int64_t>(desired));
404 }
405
406
407 static bool CompareExchangeStrongSequentiallyConsistent(volatile T* loc,
408 T expected_value, T desired_value) {
409 // sizeof(T) == 8
410 volatile int64_t* loc_ptr = reinterpret_cast<volatile int64_t*>(loc);
411 return QuasiAtomic::Cas64(
412 reinterpret_cast<int64_t>(expected_value),
413 reinterpret_cast<int64_t>(desired_value), loc_ptr);
414 }
415};
416
417template<typename T>
418class Atomic {
Hans Boehm30359612014-05-21 17:46:23 -0700419 private:
420 COMPILE_ASSERT(sizeof(T) <= 4 || sizeof(T) == 8, bad_atomic_arg);
421
422 public:
423 Atomic<T>() : value_(0) { }
424
425 explicit Atomic<T>(T value) : value_(value) { }
426
427 // Load from memory without ordering or synchronization constraints.
428 T LoadRelaxed() const {
Hans Boehma1ec0652014-06-06 17:13:03 -0700429 return AtomicHelper<sizeof(T), T>::LoadRelaxed(&value_);
Hans Boehm30359612014-05-21 17:46:23 -0700430 }
431
432 // Word tearing allowed, but may race.
433 T LoadJavaData() const {
434 return value_;
435 }
436
437 // Load from memory with a total ordering.
438 T LoadSequentiallyConsistent() const;
439
440 // Store to memory without ordering or synchronization constraints.
441 void StoreRelaxed(T desired) {
Hans Boehma1ec0652014-06-06 17:13:03 -0700442 AtomicHelper<sizeof(T), T>::StoreRelaxed(&value_, desired);
Hans Boehm30359612014-05-21 17:46:23 -0700443 }
444
445 // Word tearing allowed, but may race.
446 void StoreJavaData(T desired) {
447 value_ = desired;
448 }
449
450 // Store to memory with release ordering.
451 void StoreRelease(T desired);
452
453 // Store to memory with a total ordering.
454 void StoreSequentiallyConsistent(T desired);
455
456 // Atomically replace the value with desired value if it matches the expected value.
457 // Participates in total ordering of atomic operations.
458 bool CompareExchangeStrongSequentiallyConsistent(T expected_value, T desired_value) {
Hans Boehma1ec0652014-06-06 17:13:03 -0700459 return AtomicHelper<sizeof(T), T>::
Hans Boehm30359612014-05-21 17:46:23 -0700460 CompareExchangeStrongSequentiallyConsistent(&value_, expected_value, desired_value);
461 }
462
463 // The same, but may fail spuriously.
464 bool CompareExchangeWeakSequentiallyConsistent(T expected_value, T desired_value) {
465 // TODO: Take advantage of the fact that it may fail spuriously.
Hans Boehma1ec0652014-06-06 17:13:03 -0700466 return AtomicHelper<sizeof(T), T>::
Hans Boehm30359612014-05-21 17:46:23 -0700467 CompareExchangeStrongSequentiallyConsistent(&value_, expected_value, desired_value);
468 }
469
470 // Atomically replace the value with desired value if it matches the expected value. Doesn't
471 // imply ordering or synchronization constraints.
472 bool CompareExchangeStrongRelaxed(T expected_value, T desired_value) {
473 // TODO: make this relaxed.
474 return CompareExchangeStrongSequentiallyConsistent(expected_value, desired_value);
475 }
476
477 // The same, but may fail spuriously.
478 bool CompareExchangeWeakRelaxed(T expected_value, T desired_value) {
479 // TODO: Take advantage of the fact that it may fail spuriously.
480 // TODO: make this relaxed.
481 return CompareExchangeStrongSequentiallyConsistent(expected_value, desired_value);
482 }
483
484 // Atomically replace the value with desired value if it matches the expected value. Prior accesses
485 // made to other memory locations by the thread that did the release become visible in this
486 // thread.
487 bool CompareExchangeWeakAcquire(T expected_value, T desired_value) {
488 // TODO: make this acquire.
489 return CompareExchangeWeakSequentiallyConsistent(expected_value, desired_value);
490 }
491
492 // Atomically replace the value with desired value if it matches the expected value. Prior accesses
493 // to other memory locations become visible to the threads that do a consume or an acquire on the
494 // same location.
495 bool CompareExchangeWeakRelease(T expected_value, T desired_value) {
496 // TODO: make this release.
497 return CompareExchangeWeakSequentiallyConsistent(expected_value, desired_value);
498 }
499
500 volatile T* Address() {
501 return &value_;
502 }
503
504 T FetchAndAddSequentiallyConsistent(const T value) {
505 if (sizeof(T) <= 4) {
506 return __sync_fetch_and_add(&value_, value); // Return old value.
507 } else {
508 T expected;
509 do {
510 expected = LoadRelaxed();
511 } while (!CompareExchangeWeakSequentiallyConsistent(expected, expected + value));
512 return expected;
513 }
514 }
515
516 T FetchAndSubSequentiallyConsistent(const T value) {
517 if (sizeof(T) <= 4) {
518 return __sync_fetch_and_sub(&value_, value); // Return old value.
519 } else {
520 return FetchAndAddSequentiallyConsistent(-value);
521 }
522 }
523
524 T operator++() { // Prefix operator.
525 if (sizeof(T) <= 4) {
526 return __sync_add_and_fetch(&value_, 1); // Return new value.
527 } else {
528 return FetchAndAddSequentiallyConsistent(1) + 1;
529 }
530 }
531
532 T operator++(int) { // Postfix operator.
533 return FetchAndAddSequentiallyConsistent(1);
534 }
535
536 T operator--() { // Prefix operator.
537 if (sizeof(T) <= 4) {
538 return __sync_sub_and_fetch(&value_, 1); // Return new value.
539 } else {
540 return FetchAndSubSequentiallyConsistent(1) - 1;
541 }
542 }
543
544 T operator--(int) { // Postfix operator.
545 return FetchAndSubSequentiallyConsistent(1);
546 }
547
548 static T MaxValue() {
549 return std::numeric_limits<T>::max();
550 }
551
552
553 private:
554 volatile T value_;
555};
556#endif
557
558typedef Atomic<int32_t> AtomicInteger;
559
560COMPILE_ASSERT(sizeof(AtomicInteger) == sizeof(int32_t), weird_atomic_int_size);
561COMPILE_ASSERT(alignof(AtomicInteger) == alignof(int32_t),
562 atomic_int_alignment_differs_from_that_of_underlying_type);
Hans Boehma1ec0652014-06-06 17:13:03 -0700563COMPILE_ASSERT(sizeof(Atomic<int64_t>) == sizeof(int64_t), weird_atomic_int64_size);
Hans Boehm2f4a2ed2014-06-06 18:17:43 -0700564#if defined(__LP64__)
565 COMPILE_ASSERT(alignof(Atomic<int64_t>) == alignof(int64_t),
566 atomic_int64_alignment_differs_from_that_of_underlying_type);
567#endif
568// The above fails on x86-32.
569// This is OK, since we explicitly arrange for alignment of 8-byte fields.
Hans Boehm30359612014-05-21 17:46:23 -0700570
571
Ian Rogers3e5cf302014-05-20 16:40:37 -0700572#if !ART_HAVE_STDATOMIC
573template<typename T>
574inline T Atomic<T>::LoadSequentiallyConsistent() const {
575 T result = value_;
Hans Boehm30359612014-05-21 17:46:23 -0700576 if (sizeof(T) != 8 || !QuasiAtomic::LongAtomicsUseMutexes()) {
577 QuasiAtomic::ThreadFenceAcquire();
578 // We optimistically assume this suffices for store atomicity.
579 // On ARMv8 we strengthen ThreadFenceAcquire to make that true.
580 }
Ian Rogers3e5cf302014-05-20 16:40:37 -0700581 return result;
582}
583
584template<typename T>
Hans Boehm30359612014-05-21 17:46:23 -0700585inline void Atomic<T>::StoreRelease(T desired) {
586 if (sizeof(T) != 8 || !QuasiAtomic::LongAtomicsUseMutexes()) {
587 QuasiAtomic::ThreadFenceRelease();
588 }
589 StoreRelaxed(desired);
590}
591
592template<typename T>
Ian Rogers3e5cf302014-05-20 16:40:37 -0700593inline void Atomic<T>::StoreSequentiallyConsistent(T desired) {
Hans Boehm30359612014-05-21 17:46:23 -0700594 if (sizeof(T) != 8 || !QuasiAtomic::LongAtomicsUseMutexes()) {
595 QuasiAtomic::ThreadFenceRelease();
596 }
597 StoreRelaxed(desired);
598 if (sizeof(T) != 8 || !QuasiAtomic::LongAtomicsUseMutexes()) {
599 QuasiAtomic::ThreadFenceSequentiallyConsistent();
600 }
Ian Rogers3e5cf302014-05-20 16:40:37 -0700601}
602
603#endif
604
Elliott Hughes5ea047b2011-09-13 14:38:18 -0700605} // namespace art
606
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700607#endif // ART_RUNTIME_ATOMIC_H_