Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / tcmalloc / chromium / src / base / atomicops-internals-windows.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  * Author: Sanjay Ghemawat
32  */
33
34 // Implementation of atomic operations using Windows API
35 // functions.  This file should not be included directly.  Clients
36 // should instead include "base/atomicops.h".
37
38 #ifndef BASE_ATOMICOPS_INTERNALS_WINDOWS_H_
39 #define BASE_ATOMICOPS_INTERNALS_WINDOWS_H_
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include "base/abort.h"
44 #include "base/basictypes.h"  // For COMPILE_ASSERT
45
46 typedef int32 Atomic32;
47
48 #if defined(_WIN64)
49 #define BASE_HAS_ATOMIC64 1  // Use only in tests and base/atomic*
50 #endif
51
52 namespace base {
53 namespace subtle {
54
55 typedef int64 Atomic64;
56
57 // 32-bit low-level operations on any platform
58
59 extern "C" {
60 // We use windows intrinsics when we can (they seem to be supported
61 // well on MSVC 8.0 and above).  Unfortunately, in some
62 // environments, <windows.h> and <intrin.h> have conflicting
63 // declarations of some other intrinsics, breaking compilation:
64 //   http://connect.microsoft.com/VisualStudio/feedback/details/262047
65 // Therefore, we simply declare the relevant intrinsics ourself.
66
67 // MinGW has a bug in the header files where it doesn't indicate the
68 // first argument is volatile -- they're not up to date.  See
69 //   http://readlist.com/lists/lists.sourceforge.net/mingw-users/0/3861.html
70 // We have to const_cast away the volatile to avoid compiler warnings.
71 // TODO(csilvers): remove this once MinGW has updated MinGW/include/winbase.h
72 #if defined(__MINGW32__)
73 inline LONG FastInterlockedCompareExchange(volatile LONG* ptr,
74                                            LONG newval, LONG oldval) {
75   return ::InterlockedCompareExchange(const_cast<LONG*>(ptr), newval, oldval);
76 }
77 inline LONG FastInterlockedExchange(volatile LONG* ptr, LONG newval) {
78   return ::InterlockedExchange(const_cast<LONG*>(ptr), newval);
79 }
80 inline LONG FastInterlockedExchangeAdd(volatile LONG* ptr, LONG increment) {
81   return ::InterlockedExchangeAdd(const_cast<LONG*>(ptr), increment);
82 }
83
84 #elif _MSC_VER >= 1400   // intrinsics didn't work so well before MSVC 8.0
85 // Unfortunately, in some environments, <windows.h> and <intrin.h>
86 // have conflicting declarations of some intrinsics, breaking
87 // compilation.  So we declare the intrinsics we need ourselves.  See
88 //   http://connect.microsoft.com/VisualStudio/feedback/details/262047
89
90 // Don't declare the intrinsics if using Clang. Clang provides inline
91 // definitions in its Intrin.h.
92 #ifndef __clang__
93 LONG _InterlockedCompareExchange(volatile LONG* ptr, LONG newval, LONG oldval);
94 #pragma intrinsic(_InterlockedCompareExchange)
95
96 LONG _InterlockedExchange(volatile LONG* ptr, LONG newval);
97 #pragma intrinsic(_InterlockedExchange)
98
99 LONG _InterlockedExchangeAdd(volatile LONG* ptr, LONG increment);
100 #pragma intrinsic(_InterlockedExchangeAdd)
101 #endif
102
103 inline LONG FastInterlockedCompareExchange(volatile LONG* ptr,
104                                            LONG newval, LONG oldval) {
105   return _InterlockedCompareExchange(ptr, newval, oldval);
106 }
107
108 inline LONG FastInterlockedExchange(volatile LONG* ptr, LONG newval) {
109   return _InterlockedExchange(ptr, newval);
110 }
111
112 inline LONG FastInterlockedExchangeAdd(volatile LONG* ptr, LONG increment) {
113   return _InterlockedExchangeAdd(ptr, increment);
114 }
115
116 #else
117 inline LONG FastInterlockedCompareExchange(volatile LONG* ptr,
118                                            LONG newval, LONG oldval) {
119   return ::InterlockedCompareExchange(ptr, newval, oldval);
120 }
121 inline LONG FastInterlockedExchange(volatile LONG* ptr, LONG newval) {
122   return ::InterlockedExchange(ptr, newval);
123 }
124 inline LONG FastInterlockedExchangeAdd(volatile LONG* ptr, LONG increment) {
125   return ::InterlockedExchangeAdd(ptr, increment);
126 }
127
128 #endif  // ifdef __MINGW32__
129 }  // extern "C"
130
131 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
132                                          Atomic32 old_value,
133                                          Atomic32 new_value) {
134   LONG result = FastInterlockedCompareExchange(
135       reinterpret_cast<volatile LONG*>(ptr),
136       static_cast<LONG>(new_value),
137       static_cast<LONG>(old_value));
138   return static_cast<Atomic32>(result);
139 }
140
141 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
142                                          Atomic32 new_value) {
143   LONG result = FastInterlockedExchange(
144       reinterpret_cast<volatile LONG*>(ptr),
145       static_cast<LONG>(new_value));
146   return static_cast<Atomic32>(result);
147 }
148
149 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
150                                         Atomic32 increment) {
151   return FastInterlockedExchangeAdd(
152       reinterpret_cast<volatile LONG*>(ptr),
153       static_cast<LONG>(increment)) + increment;
154 }
155
156 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
157                                           Atomic32 increment) {
158   return Barrier_AtomicIncrement(ptr, increment);
159 }
160
161 }  // namespace base::subtle
162 }  // namespace base
163
164
165 // In msvc8/vs2005, winnt.h already contains a definition for
166 // MemoryBarrier in the global namespace.  Add it there for earlier
167 // versions and forward to it from within the namespace.
168 #if !(defined(_MSC_VER) && _MSC_VER >= 1400)
169 inline void MemoryBarrier() {
170   Atomic32 value = 0;
171   base::subtle::NoBarrier_AtomicExchange(&value, 0);
172                         // actually acts as a barrier in thisd implementation
173 }
174 #endif
175
176 namespace base {
177 namespace subtle {
178
179 inline void MemoryBarrier() {
180   ::MemoryBarrier();
181 }
182
183 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
184                                        Atomic32 old_value,
185                                        Atomic32 new_value) {
186   return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
187 }
188
189 inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
190                                        Atomic32 old_value,
191                                        Atomic32 new_value) {
192   return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
193 }
194
195 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
196   *ptr = value;
197 }
198
199 inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
200   NoBarrier_AtomicExchange(ptr, value);
201               // acts as a barrier in this implementation
202 }
203
204 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
205   *ptr = value; // works w/o barrier for current Intel chips as of June 2005
206   // See comments in Atomic64 version of Release_Store() below.
207 }
208
209 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
210   return *ptr;
211 }
212
213 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
214   Atomic32 value = *ptr;
215   return value;
216 }
217
218 inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
219   MemoryBarrier();
220   return *ptr;
221 }
222
223 // 64-bit operations
224
225 #if defined(_WIN64) || defined(__MINGW64__)
226
227 // 64-bit low-level operations on 64-bit platform.
228
229 COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
230
231 // These are the intrinsics needed for 64-bit operations.  Similar to the
232 // 32-bit case above.
233
234 extern "C" {
235 #if defined(__MINGW64__)
236 inline PVOID FastInterlockedCompareExchangePointer(volatile PVOID* ptr,
237                                                    PVOID newval, PVOID oldval) {
238   return ::InterlockedCompareExchangePointer(const_cast<PVOID*>(ptr),
239                                              newval, oldval);
240 }
241 inline PVOID FastInterlockedExchangePointer(volatile PVOID* ptr, PVOID newval) {
242   return ::InterlockedExchangePointer(const_cast<PVOID*>(ptr), newval);
243 }
244 inline LONGLONG FastInterlockedExchangeAdd64(volatile LONGLONG* ptr,
245                                              LONGLONG increment) {
246   return ::InterlockedExchangeAdd64(const_cast<LONGLONG*>(ptr), increment);
247 }
248
249 #elif _MSC_VER >= 1400   // intrinsics didn't work so well before MSVC 8.0
250 // Like above, we need to declare the intrinsics ourselves.
251 PVOID _InterlockedCompareExchangePointer(volatile PVOID* ptr,
252                                          PVOID newval, PVOID oldval);
253 #pragma intrinsic(_InterlockedCompareExchangePointer)
254 inline PVOID FastInterlockedCompareExchangePointer(volatile PVOID* ptr,
255                                                    PVOID newval, PVOID oldval) {
256   return _InterlockedCompareExchangePointer(const_cast<PVOID*>(ptr),
257                                             newval, oldval);
258 }
259
260 PVOID _InterlockedExchangePointer(volatile PVOID* ptr, PVOID newval);
261 #pragma intrinsic(_InterlockedExchangePointer)
262 inline PVOID FastInterlockedExchangePointer(volatile PVOID* ptr, PVOID newval) {
263   return _InterlockedExchangePointer(const_cast<PVOID*>(ptr), newval);
264 }
265
266 LONGLONG _InterlockedExchangeAdd64(volatile LONGLONG* ptr, LONGLONG increment);
267 #pragma intrinsic(_InterlockedExchangeAdd64)
268 inline LONGLONG FastInterlockedExchangeAdd64(volatile LONGLONG* ptr,
269                                              LONGLONG increment) {
270   return _InterlockedExchangeAdd64(const_cast<LONGLONG*>(ptr), increment);
271 }
272
273 #else
274 inline PVOID FastInterlockedCompareExchangePointer(volatile PVOID* ptr,
275                                                    PVOID newval, PVOID oldval) {
276   return ::InterlockedCompareExchangePointer(ptr, newval, oldval);
277 }
278 inline PVOID FastInterlockedExchangePointer(volatile PVOID* ptr, PVOID newval) {
279   return ::InterlockedExchangePointer(ptr, newval);
280 }
281 inline LONGLONG FastInterlockedExchangeAdd64(volatile LONGLONG* ptr,
282                                          LONGLONG increment) {
283   return ::InterlockedExchangeAdd64(ptr, increment);
284 }
285
286 #endif  // ifdef __MINGW64__
287 }  // extern "C"
288
289 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
290                                          Atomic64 old_value,
291                                          Atomic64 new_value) {
292   PVOID result = FastInterlockedCompareExchangePointer(
293     reinterpret_cast<volatile PVOID*>(ptr),
294     reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
295   return reinterpret_cast<Atomic64>(result);
296 }
297
298 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
299                                          Atomic64 new_value) {
300   PVOID result = FastInterlockedExchangePointer(
301     reinterpret_cast<volatile PVOID*>(ptr),
302     reinterpret_cast<PVOID>(new_value));
303   return reinterpret_cast<Atomic64>(result);
304 }
305
306 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
307                                         Atomic64 increment) {
308   return FastInterlockedExchangeAdd64(
309       reinterpret_cast<volatile LONGLONG*>(ptr),
310       static_cast<LONGLONG>(increment)) + increment;
311 }
312
313 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
314                                           Atomic64 increment) {
315   return Barrier_AtomicIncrement(ptr, increment);
316 }
317
318 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
319   *ptr = value;
320 }
321
322 inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
323   NoBarrier_AtomicExchange(ptr, value);
324               // acts as a barrier in this implementation
325 }
326
327 inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
328   *ptr = value; // works w/o barrier for current Intel chips as of June 2005
329
330   // When new chips come out, check:
331   //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
332   //  System Programming Guide, Chatper 7: Multiple-processor management,
333   //  Section 7.2, Memory Ordering.
334   // Last seen at:
335   //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
336 }
337
338 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
339   return *ptr;
340 }
341
342 inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
343   Atomic64 value = *ptr;
344   return value;
345 }
346
347 inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
348   MemoryBarrier();
349   return *ptr;
350 }
351
352 #else  // defined(_WIN64) || defined(__MINGW64__)
353
354 // 64-bit low-level operations on 32-bit platform
355
356 // TODO(vchen): The GNU assembly below must be converted to MSVC inline
357 // assembly.  Then the file should be renamed to ...-x86-msvc.h, probably.
358
359 inline void NotImplementedFatalError(const char *function_name) {
360   fprintf(stderr, "64-bit %s() not implemented on this platform\n",
361           function_name);
362   tcmalloc::Abort();
363 }
364
365 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
366                                          Atomic64 old_value,
367                                          Atomic64 new_value) {
368 #if 0 // Not implemented
369   Atomic64 prev;
370   __asm__ __volatile__("movl (%3), %%ebx\n\t"    // Move 64-bit new_value into
371                        "movl 4(%3), %%ecx\n\t"   // ecx:ebx
372                        "lock; cmpxchg8b %1\n\t"  // If edx:eax (old_value) same
373                        : "=A" (prev)             // as contents of ptr:
374                        : "m" (*ptr),             //   ecx:ebx => ptr
375                          "0" (old_value),        // else:
376                          "r" (&new_value)        //   old *ptr => edx:eax
377                        : "memory", "%ebx", "%ecx");
378   return prev;
379 #else
380   NotImplementedFatalError("NoBarrier_CompareAndSwap");
381   return 0;
382 #endif
383 }
384
385 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
386                                          Atomic64 new_value) {
387 #if 0 // Not implemented
388   __asm__ __volatile__(
389                        "movl (%2), %%ebx\n\t"    // Move 64-bit new_value into
390                        "movl 4(%2), %%ecx\n\t"   // ecx:ebx
391                        "0:\n\t"
392                        "movl %1, %%eax\n\t"      // Read contents of ptr into
393                        "movl 4%1, %%edx\n\t"     // edx:eax
394                        "lock; cmpxchg8b %1\n\t"  // Attempt cmpxchg; if *ptr
395                        "jnz 0b\n\t"              // is no longer edx:eax, loop
396                        : "=A" (new_value)
397                        : "m" (*ptr),
398                          "r" (&new_value)
399                        : "memory", "%ebx", "%ecx");
400   return new_value;  // Now it's the previous value.
401 #else
402   NotImplementedFatalError("NoBarrier_AtomicExchange");
403   return 0;
404 #endif
405 }
406
407 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
408                                           Atomic64 increment) {
409 #if 0 // Not implemented
410   Atomic64 temp = increment;
411   __asm__ __volatile__(
412                        "0:\n\t"
413                        "movl (%3), %%ebx\n\t"    // Move 64-bit increment into
414                        "movl 4(%3), %%ecx\n\t"   // ecx:ebx
415                        "movl (%2), %%eax\n\t"    // Read contents of ptr into
416                        "movl 4(%2), %%edx\n\t"   // edx:eax
417                        "add %%eax, %%ebx\n\t"    // sum => ecx:ebx
418                        "adc %%edx, %%ecx\n\t"    // edx:eax still has old *ptr
419                        "lock; cmpxchg8b (%2)\n\t"// Attempt cmpxchg; if *ptr
420                        "jnz 0b\n\t"              // is no longer edx:eax, loop
421                        : "=A"(temp), "+m"(*ptr)
422                        : "D" (ptr), "S" (&increment)
423                        : "memory", "%ebx", "%ecx");
424   // temp now contains the previous value of *ptr
425   return temp + increment;
426 #else
427   NotImplementedFatalError("NoBarrier_AtomicIncrement");
428   return 0;
429 #endif
430 }
431
432 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
433                                         Atomic64 increment) {
434 #if 0 // Not implemented
435   Atomic64 new_val = NoBarrier_AtomicIncrement(ptr, increment);
436   if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
437     __asm__ __volatile__("lfence" : : : "memory");
438   }
439   return new_val;
440 #else
441   NotImplementedFatalError("Barrier_AtomicIncrement");
442   return 0;
443 #endif
444 }
445
446 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
447 #if 0 // Not implemented
448   __asm {
449     mov mm0, value;  // Use mmx reg for 64-bit atomic moves
450     mov ptr, mm0;
451     emms;            // Empty mmx state to enable FP registers
452   }
453 #else
454   NotImplementedFatalError("NoBarrier_Store");
455 #endif
456 }
457
458 inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
459   NoBarrier_AtomicExchange(ptr, value);
460               // acts as a barrier in this implementation
461 }
462
463 inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
464   NoBarrier_Store(ptr, value);
465 }
466
467 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
468 #if 0 // Not implemented
469   Atomic64 value;
470   __asm {
471     mov mm0, ptr;    // Use mmx reg for 64-bit atomic moves
472     mov value, mm0;
473     emms;            // Empty mmx state to enable FP registers
474   }
475   return value;
476 #else
477   NotImplementedFatalError("NoBarrier_Store");
478   return 0;
479 #endif
480 }
481
482 inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
483   Atomic64 value = NoBarrier_Load(ptr);
484   return value;
485 }
486
487 inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
488   MemoryBarrier();
489   return NoBarrier_Load(ptr);
490 }
491
492 #endif  // defined(_WIN64) || defined(__MINGW64__)
493
494
495 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
496                                        Atomic64 old_value,
497                                        Atomic64 new_value) {
498   return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
499 }
500
501 inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
502                                        Atomic64 old_value,
503                                        Atomic64 new_value) {
504   return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
505 }
506
507 }  // namespace base::subtle
508 }  // namespace base
509
510 #endif  // BASE_ATOMICOPS_INTERNALS_WINDOWS_H_