- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / tcmalloc / chromium / src / base / atomicops-internals-macosx.h
1 /* Copyright (c) 2006, Google Inc.
2  * All rights reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 // Implementation of atomic operations for Mac OS X.  This file should not
32 // be included directly.  Clients should instead include
33 // "base/atomicops.h".
34
35 #ifndef BASE_ATOMICOPS_INTERNALS_MACOSX_H_
36 #define BASE_ATOMICOPS_INTERNALS_MACOSX_H_
37
38 typedef int32_t Atomic32;
39
40 // MacOS uses long for intptr_t, AtomicWord and Atomic32 are always different
41 // on the Mac, even when they are the same size.  Similarly, on __ppc64__,
42 // AtomicWord and Atomic64 are always different.  Thus, we need explicit
43 // casting.
44 #ifdef __LP64__
45 #define AtomicWordCastType base::subtle::Atomic64
46 #else
47 #define AtomicWordCastType Atomic32
48 #endif
49
50 #if defined(__LP64__) || defined(__i386__)
51 #define BASE_HAS_ATOMIC64 1  // Use only in tests and base/atomic*
52 #endif
53
54 #include <libkern/OSAtomic.h>
55
56 namespace base {
57 namespace subtle {
58
59 #if !defined(__LP64__) && defined(__ppc__)
60
61 // The Mac 64-bit OSAtomic implementations are not available for 32-bit PowerPC,
62 // while the underlying assembly instructions are available only some
63 // implementations of PowerPC.
64
65 // The following inline functions will fail with the error message at compile
66 // time ONLY IF they are called.  So it is safe to use this header if user
67 // code only calls AtomicWord and Atomic32 operations.
68 //
69 // NOTE(vchen): Implementation notes to implement the atomic ops below may
70 // be found in "PowerPC Virtual Environment Architecture, Book II,
71 // Version 2.02", January 28, 2005, Appendix B, page 46.  Unfortunately,
72 // extra care must be taken to ensure data are properly 8-byte aligned, and
73 // that data are returned correctly according to Mac OS X ABI specs.
74
75 inline int64_t OSAtomicCompareAndSwap64(
76     int64_t oldValue, int64_t newValue, int64_t *theValue) {
77   __asm__ __volatile__(
78       "_OSAtomicCompareAndSwap64_not_supported_for_32_bit_ppc\n\t");
79   return 0;
80 }
81
82 inline int64_t OSAtomicAdd64(int64_t theAmount, int64_t *theValue) {
83   __asm__ __volatile__(
84       "_OSAtomicAdd64_not_supported_for_32_bit_ppc\n\t");
85   return 0;
86 }
87
88 inline int64_t OSAtomicCompareAndSwap64Barrier(
89     int64_t oldValue, int64_t newValue, int64_t *theValue) {
90   int64_t prev = OSAtomicCompareAndSwap64(oldValue, newValue, theValue);
91   OSMemoryBarrier();
92   return prev;
93 }
94
95 inline int64_t OSAtomicAdd64Barrier(
96     int64_t theAmount, int64_t *theValue) {
97   int64_t new_val = OSAtomicAdd64(theAmount, theValue);
98   OSMemoryBarrier();
99   return new_val;
100 }
101 #endif
102
103 typedef int64_t Atomic64;
104
105 inline void MemoryBarrier() {
106   OSMemoryBarrier();
107 }
108
109 // 32-bit Versions.
110
111 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
112                                          Atomic32 old_value,
113                                          Atomic32 new_value) {
114   Atomic32 prev_value;
115   do {
116     if (OSAtomicCompareAndSwap32(old_value, new_value,
117                                  const_cast<Atomic32*>(ptr))) {
118       return old_value;
119     }
120     prev_value = *ptr;
121   } while (prev_value == old_value);
122   return prev_value;
123 }
124
125 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
126                                          Atomic32 new_value) {
127   Atomic32 old_value;
128   do {
129     old_value = *ptr;
130   } while (!OSAtomicCompareAndSwap32(old_value, new_value,
131                                      const_cast<Atomic32*>(ptr)));
132   return old_value;
133 }
134
135 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
136                                           Atomic32 increment) {
137   return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
138 }
139
140 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
141                                           Atomic32 increment) {
142   return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
143 }
144
145 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
146                                        Atomic32 old_value,
147                                        Atomic32 new_value) {
148   Atomic32 prev_value;
149   do {
150     if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
151                                         const_cast<Atomic32*>(ptr))) {
152       return old_value;
153     }
154     prev_value = *ptr;
155   } while (prev_value == old_value);
156   return prev_value;
157 }
158
159 inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
160                                        Atomic32 old_value,
161                                        Atomic32 new_value) {
162   return Acquire_CompareAndSwap(ptr, old_value, new_value);
163 }
164
165 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
166   *ptr = value;
167 }
168
169 inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
170   *ptr = value;
171   MemoryBarrier();
172 }
173
174 inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
175   MemoryBarrier();
176   *ptr = value;
177 }
178
179 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
180   return *ptr;
181 }
182
183 inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
184   Atomic32 value = *ptr;
185   MemoryBarrier();
186   return value;
187 }
188
189 inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
190   MemoryBarrier();
191   return *ptr;
192 }
193
194 // 64-bit version
195
196 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
197                                          Atomic64 old_value,
198                                          Atomic64 new_value) {
199   Atomic64 prev_value;
200   do {
201     if (OSAtomicCompareAndSwap64(old_value, new_value,
202                                  const_cast<Atomic64*>(ptr))) {
203       return old_value;
204     }
205     prev_value = *ptr;
206   } while (prev_value == old_value);
207   return prev_value;
208 }
209
210 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
211                                          Atomic64 new_value) {
212   Atomic64 old_value;
213   do {
214     old_value = *ptr;
215   } while (!OSAtomicCompareAndSwap64(old_value, new_value,
216                                      const_cast<Atomic64*>(ptr)));
217   return old_value;
218 }
219
220 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
221                                           Atomic64 increment) {
222   return OSAtomicAdd64(increment, const_cast<Atomic64*>(ptr));
223 }
224
225 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
226                                         Atomic64 increment) {
227   return OSAtomicAdd64Barrier(increment, const_cast<Atomic64*>(ptr));
228 }
229
230 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
231                                        Atomic64 old_value,
232                                        Atomic64 new_value) {
233   Atomic64 prev_value;
234   do {
235     if (OSAtomicCompareAndSwap64Barrier(old_value, new_value,
236                                         const_cast<Atomic64*>(ptr))) {
237       return old_value;
238     }
239     prev_value = *ptr;
240   } while (prev_value == old_value);
241   return prev_value;
242 }
243
244 inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
245                                        Atomic64 old_value,
246                                        Atomic64 new_value) {
247   // The lib kern interface does not distinguish between
248   // Acquire and Release memory barriers; they are equivalent.
249   return Acquire_CompareAndSwap(ptr, old_value, new_value);
250 }
251
252 #ifdef __LP64__
253
254 // 64-bit implementation on 64-bit platform
255
256 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
257   *ptr = value;
258 }
259
260 inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
261   *ptr = value;
262   MemoryBarrier();
263 }
264
265 inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
266   MemoryBarrier();
267   *ptr = value;
268 }
269
270 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
271   return *ptr;
272 }
273
274 inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
275   Atomic64 value = *ptr;
276   MemoryBarrier();
277   return value;
278 }
279
280 inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
281   MemoryBarrier();
282   return *ptr;
283 }
284
285 #else
286
287 // 64-bit implementation on 32-bit platform
288
289 #if defined(__ppc__)
290
291 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
292    __asm__ __volatile__(
293        "_NoBarrier_Store_not_supported_for_32_bit_ppc\n\t");
294 }
295
296 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
297    __asm__ __volatile__(
298        "_NoBarrier_Load_not_supported_for_32_bit_ppc\n\t");
299    return 0;
300 }
301
302 #elif defined(__i386__)
303
304 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
305   __asm__ __volatile__("movq %1, %%mm0\n\t"    // Use mmx reg for 64-bit atomic
306                        "movq %%mm0, %0\n\t"  // moves (ptr could be read-only)
307                        "emms\n\t"              // Reset FP registers
308                        : "=m" (*ptr)
309                        : "m" (value)
310                        : // mark the FP stack and mmx registers as clobbered
311                          "st", "st(1)", "st(2)", "st(3)", "st(4)",
312                          "st(5)", "st(6)", "st(7)", "mm0", "mm1",
313                          "mm2", "mm3", "mm4", "mm5", "mm6", "mm7");
314
315 }
316
317 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
318   Atomic64 value;
319   __asm__ __volatile__("movq %1, %%mm0\n\t"  // Use mmx reg for 64-bit atomic
320                        "movq %%mm0, %0\n\t"  // moves (ptr could be read-only)
321                        "emms\n\t"            // Reset FP registers
322                        : "=m" (value)
323                        : "m" (*ptr)
324                        : // mark the FP stack and mmx registers as clobbered
325                          "st", "st(1)", "st(2)", "st(3)", "st(4)",
326                          "st(5)", "st(6)", "st(7)", "mm0", "mm1",
327                          "mm2", "mm3", "mm4", "mm5", "mm6", "mm7");
328
329   return value;
330 }
331 #endif
332
333
334 inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
335   NoBarrier_Store(ptr, value);
336   MemoryBarrier();
337 }
338
339 inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
340   MemoryBarrier();
341   NoBarrier_Store(ptr, value);
342 }
343
344 inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
345   Atomic64 value = NoBarrier_Load(ptr);
346   MemoryBarrier();
347   return value;
348 }
349
350 inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
351   MemoryBarrier();
352   return NoBarrier_Load(ptr);
353 }
354 #endif  // __LP64__
355
356 }   // namespace base::subtle
357 }   // namespace base
358
359 #endif  // BASE_ATOMICOPS_INTERNALS_MACOSX_H_