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