1a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// Copyright 2010 the V8 project authors. All rights reserved.
23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// Use of this source code is governed by a BSD-style license that can be
33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// found in the LICENSE file.
4a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
5a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// The routines exported by this module are subtle.  If you use them, even if
6a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// you get the code right, it will depend on careful reasoning about atomicity
7a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// and memory ordering; it will be less readable, and harder to maintain.  If
8a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// you plan to use these routines, you should have a good reason, such as solid
9a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// evidence that performance would otherwise suffer, or there being no
10a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// alternative.  You should assume only properties explicitly guaranteed by the
11a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// specifications in this file.  You are almost certainly _not_ writing code
12a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// just for the x86; if you assume x86 semantics, x86 hardware bugs and
13a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// implementations on other archtectures will cause your code to break.  If you
14a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// do not know what you are doing, avoid these routines, and use a Mutex.
15a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//
16a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// It is incorrect to make direct assignments to/from an atomic variable.
17a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// You should use one of the Load or Store routines.  The NoBarrier
18a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// versions are provided when no barriers are needed:
19a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//   NoBarrier_Store()
20a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//   NoBarrier_Load()
21a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// Although there are currently no compiler enforcement, you are encouraged
22a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// to use these.
23a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//
24a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
251e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#ifndef V8_BASE_ATOMICOPS_H_
261e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#define V8_BASE_ATOMICOPS_H_
27a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
28d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org#include "include/v8stdint.h"
29196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/base/build_config.h"
30a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
31ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org#if defined(_WIN32) && defined(V8_HOST_ARCH_64_BIT)
32ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org// windows.h #defines this (only on x64). This causes problems because the
33ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org// public API also uses MemoryBarrier at the public name for this fence. So, on
34ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org// X64, undef it, and call its documented
35ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
36ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org// implementation directly.
37ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org#undef MemoryBarrier
38ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org#endif
39ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
40a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgnamespace v8 {
411e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.orgnamespace base {
42a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
435b080567cf135f6dbaf23973ba6b6fa1d6af83b3machenbach@chromium.orgtypedef char Atomic8;
44a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgtypedef int32_t Atomic32;
45a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#ifdef V8_HOST_ARCH_64_BIT
46a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// We need to be able to go between Atomic64 and AtomicWord implicitly.  This
47a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// means Atomic64 and AtomicWord should be the same type on 64-bit.
48ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org#if defined(__ILP32__)
49a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgtypedef int64_t Atomic64;
50a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#else
51a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgtypedef intptr_t Atomic64;
52a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#endif
53a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#endif
54a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
55a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// Use AtomicWord for a machine-sized pointer.  It will use the Atomic32 or
56a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// Atomic64 routines below, depending on your architecture.
57a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgtypedef intptr_t AtomicWord;
58a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
59a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// Atomically execute:
60a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//      result = *ptr;
61a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//      if (*ptr == old_value)
62a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//        *ptr = new_value;
63a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//      return result;
64a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//
65a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
66a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// Always return the old value of "*ptr"
67a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org//
68a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// This routine implies no memory barriers.
69a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
70a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                  Atomic32 old_value,
71a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                  Atomic32 new_value);
72a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
73a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// Atomically store new_value into *ptr, returning the previous value held in
74a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// *ptr.  This routine implies no memory barriers.
75a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
76a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
77a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// Atomically increment *ptr by "increment".  Returns the new value of
78a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// *ptr with the increment applied.  This routine implies no memory barriers.
79a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
80a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
81a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
82a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                 Atomic32 increment);
83a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
84a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// These following lower-level operations are typically useful only to people
85a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// implementing higher-level synchronization operations like spinlocks,
86a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// mutexes, and condition-variables.  They combine CompareAndSwap(), a load, or
87a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// a store with appropriate memory-ordering instructions.  "Acquire" operations
88a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// ensure that no later memory access can be reordered ahead of the operation.
89a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// "Release" operations ensure that no previous memory access can be reordered
90a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// after the operation.  "Barrier" operations have both "Acquire" and "Release"
91a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
92a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// access.
93a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
94a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                Atomic32 old_value,
95a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                Atomic32 new_value);
96a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
97a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                Atomic32 old_value,
98a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                Atomic32 new_value);
99a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
100a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid MemoryBarrier();
1015b080567cf135f6dbaf23973ba6b6fa1d6af83b3machenbach@chromium.orgvoid NoBarrier_Store(volatile Atomic8* ptr, Atomic8 value);
102a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
103a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
104a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid Release_Store(volatile Atomic32* ptr, Atomic32 value);
105a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
1065b080567cf135f6dbaf23973ba6b6fa1d6af83b3machenbach@chromium.orgAtomic8 NoBarrier_Load(volatile const Atomic8* ptr);
107a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic32 NoBarrier_Load(volatile const Atomic32* ptr);
108a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic32 Acquire_Load(volatile const Atomic32* ptr);
109a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic32 Release_Load(volatile const Atomic32* ptr);
110a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
111a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// 64-bit atomic operations (only available on 64-bit processors).
112a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#ifdef V8_HOST_ARCH_64_BIT
113a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
114a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                  Atomic64 old_value,
115a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                  Atomic64 new_value);
116a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
117a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
118a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
119a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
120a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
121a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                Atomic64 old_value,
122a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                Atomic64 new_value);
123a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
124a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                Atomic64 old_value,
125a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                                Atomic64 new_value);
126a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
127a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
128a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid Release_Store(volatile Atomic64* ptr, Atomic64 value);
129a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic64 NoBarrier_Load(volatile const Atomic64* ptr);
130a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic64 Acquire_Load(volatile const Atomic64* ptr);
131a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgAtomic64 Release_Load(volatile const Atomic64* ptr);
132a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#endif  // V8_HOST_ARCH_64_BIT
133a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
1341e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org} }  // namespace v8::base
135a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
136a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org// Include our platform specific implementation.
137fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org#if defined(THREAD_SANITIZER)
1381e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#include "src/base/atomicops_internals_tsan.h"
139e0e1b0d3e70c933d36ed381d511e9fda39f2a751mstarzinger@chromium.org#elif defined(_MSC_VER) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
1401e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#include "src/base/atomicops_internals_x86_msvc.h"
141ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org#elif defined(__APPLE__)
1421e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#include "src/base/atomicops_internals_mac.h"
143fa0c3c69b9d632e5730bdd9c745c375beef5e54dmachenbach@chromium.org#elif defined(__GNUC__) && V8_HOST_ARCH_ARM64
1441e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#include "src/base/atomicops_internals_arm64_gcc.h"
14593a47f4837f2137c8d8349250fd8e91da3108126jkummerow@chromium.org#elif defined(__GNUC__) && V8_HOST_ARCH_ARM
1461e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#include "src/base/atomicops_internals_arm_gcc.h"
147ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org#elif defined(__GNUC__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
1481e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#include "src/base/atomicops_internals_x86_gcc.h"
14993a47f4837f2137c8d8349250fd8e91da3108126jkummerow@chromium.org#elif defined(__GNUC__) && V8_HOST_ARCH_MIPS
1501e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#include "src/base/atomicops_internals_mips_gcc.h"
15112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#elif defined(__GNUC__) && V8_HOST_ARCH_MIPS64
15212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include "src/base/atomicops_internals_mips64_gcc.h"
153a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#else
154a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#error "Atomic operations are not supported on your platform"
155a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#endif
156a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
157ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org// On some platforms we need additional declarations to make
158ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org// AtomicWord compatible with our other Atomic* types.
159ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org#if defined(__APPLE__) || defined(__OpenBSD__)
1601e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#include "src/base/atomicops_internals_atomicword_compat.h"
161ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org#endif
162ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1631e2d50cf3d94ff48285da107b7a9da1ad0fc873dmachenbach@chromium.org#endif  // V8_BASE_ATOMICOPS_H_
164