1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/chromium/base/atomicops_internals_x86_gcc.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,269 @@ 1.4 +// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +// This file is an internal atomic implementation, use base/atomicops.h instead. 1.9 + 1.10 +#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_ 1.11 +#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_ 1.12 + 1.13 +#include "base/base_export.h" 1.14 + 1.15 +// This struct is not part of the public API of this module; clients may not 1.16 +// use it. (However, it's exported via BASE_EXPORT because clients implicitly 1.17 +// do use it at link time by inlining these functions.) 1.18 +// Features of this x86. Values may not be correct before main() is run, 1.19 +// but are set conservatively. 1.20 +struct AtomicOps_x86CPUFeatureStruct { 1.21 + bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence 1.22 + // after acquire compare-and-swap. 1.23 + bool has_sse2; // Processor has SSE2. 1.24 +}; 1.25 +BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct 1.26 + AtomicOps_Internalx86CPUFeatures; 1.27 + 1.28 +#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") 1.29 + 1.30 +namespace base { 1.31 +namespace subtle { 1.32 + 1.33 +// 32-bit low-level operations on any platform. 1.34 + 1.35 +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, 1.36 + Atomic32 old_value, 1.37 + Atomic32 new_value) { 1.38 + Atomic32 prev; 1.39 + __asm__ __volatile__("lock; cmpxchgl %1,%2" 1.40 + : "=a" (prev) 1.41 + : "q" (new_value), "m" (*ptr), "0" (old_value) 1.42 + : "memory"); 1.43 + return prev; 1.44 +} 1.45 + 1.46 +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, 1.47 + Atomic32 new_value) { 1.48 + __asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg. 1.49 + : "=r" (new_value) 1.50 + : "m" (*ptr), "0" (new_value) 1.51 + : "memory"); 1.52 + return new_value; // Now it's the previous value. 1.53 +} 1.54 + 1.55 +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, 1.56 + Atomic32 increment) { 1.57 + Atomic32 temp = increment; 1.58 + __asm__ __volatile__("lock; xaddl %0,%1" 1.59 + : "+r" (temp), "+m" (*ptr) 1.60 + : : "memory"); 1.61 + // temp now holds the old value of *ptr 1.62 + return temp + increment; 1.63 +} 1.64 + 1.65 +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, 1.66 + Atomic32 increment) { 1.67 + Atomic32 temp = increment; 1.68 + __asm__ __volatile__("lock; xaddl %0,%1" 1.69 + : "+r" (temp), "+m" (*ptr) 1.70 + : : "memory"); 1.71 + // temp now holds the old value of *ptr 1.72 + if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { 1.73 + __asm__ __volatile__("lfence" : : : "memory"); 1.74 + } 1.75 + return temp + increment; 1.76 +} 1.77 + 1.78 +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, 1.79 + Atomic32 old_value, 1.80 + Atomic32 new_value) { 1.81 + Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); 1.82 + if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { 1.83 + __asm__ __volatile__("lfence" : : : "memory"); 1.84 + } 1.85 + return x; 1.86 +} 1.87 + 1.88 +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, 1.89 + Atomic32 old_value, 1.90 + Atomic32 new_value) { 1.91 + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); 1.92 +} 1.93 + 1.94 +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { 1.95 + *ptr = value; 1.96 +} 1.97 + 1.98 +#if defined(__x86_64__) 1.99 + 1.100 +// 64-bit implementations of memory barrier can be simpler, because it 1.101 +// "mfence" is guaranteed to exist. 1.102 +inline void MemoryBarrier() { 1.103 + __asm__ __volatile__("mfence" : : : "memory"); 1.104 +} 1.105 + 1.106 +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { 1.107 + *ptr = value; 1.108 + MemoryBarrier(); 1.109 +} 1.110 + 1.111 +#else 1.112 + 1.113 +inline void MemoryBarrier() { 1.114 + if (AtomicOps_Internalx86CPUFeatures.has_sse2) { 1.115 + __asm__ __volatile__("mfence" : : : "memory"); 1.116 + } else { // mfence is faster but not present on PIII 1.117 + Atomic32 x = 0; 1.118 + NoBarrier_AtomicExchange(&x, 0); // acts as a barrier on PIII 1.119 + } 1.120 +} 1.121 + 1.122 +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { 1.123 + if (AtomicOps_Internalx86CPUFeatures.has_sse2) { 1.124 + *ptr = value; 1.125 + __asm__ __volatile__("mfence" : : : "memory"); 1.126 + } else { 1.127 + NoBarrier_AtomicExchange(ptr, value); 1.128 + // acts as a barrier on PIII 1.129 + } 1.130 +} 1.131 +#endif 1.132 + 1.133 +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { 1.134 + ATOMICOPS_COMPILER_BARRIER(); 1.135 + *ptr = value; // An x86 store acts as a release barrier. 1.136 + // See comments in Atomic64 version of Release_Store(), below. 1.137 +} 1.138 + 1.139 +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { 1.140 + return *ptr; 1.141 +} 1.142 + 1.143 +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { 1.144 + Atomic32 value = *ptr; // An x86 load acts as a acquire barrier. 1.145 + // See comments in Atomic64 version of Release_Store(), below. 1.146 + ATOMICOPS_COMPILER_BARRIER(); 1.147 + return value; 1.148 +} 1.149 + 1.150 +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { 1.151 + MemoryBarrier(); 1.152 + return *ptr; 1.153 +} 1.154 + 1.155 +#if defined(__x86_64__) 1.156 + 1.157 +// 64-bit low-level operations on 64-bit platform. 1.158 + 1.159 +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, 1.160 + Atomic64 old_value, 1.161 + Atomic64 new_value) { 1.162 + Atomic64 prev; 1.163 + __asm__ __volatile__("lock; cmpxchgq %1,%2" 1.164 + : "=a" (prev) 1.165 + : "q" (new_value), "m" (*ptr), "0" (old_value) 1.166 + : "memory"); 1.167 + return prev; 1.168 +} 1.169 + 1.170 +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, 1.171 + Atomic64 new_value) { 1.172 + __asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg. 1.173 + : "=r" (new_value) 1.174 + : "m" (*ptr), "0" (new_value) 1.175 + : "memory"); 1.176 + return new_value; // Now it's the previous value. 1.177 +} 1.178 + 1.179 +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, 1.180 + Atomic64 increment) { 1.181 + Atomic64 temp = increment; 1.182 + __asm__ __volatile__("lock; xaddq %0,%1" 1.183 + : "+r" (temp), "+m" (*ptr) 1.184 + : : "memory"); 1.185 + // temp now contains the previous value of *ptr 1.186 + return temp + increment; 1.187 +} 1.188 + 1.189 +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, 1.190 + Atomic64 increment) { 1.191 + Atomic64 temp = increment; 1.192 + __asm__ __volatile__("lock; xaddq %0,%1" 1.193 + : "+r" (temp), "+m" (*ptr) 1.194 + : : "memory"); 1.195 + // temp now contains the previous value of *ptr 1.196 + if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { 1.197 + __asm__ __volatile__("lfence" : : : "memory"); 1.198 + } 1.199 + return temp + increment; 1.200 +} 1.201 + 1.202 +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { 1.203 + *ptr = value; 1.204 +} 1.205 + 1.206 +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { 1.207 + *ptr = value; 1.208 + MemoryBarrier(); 1.209 +} 1.210 + 1.211 +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { 1.212 + ATOMICOPS_COMPILER_BARRIER(); 1.213 + 1.214 + *ptr = value; // An x86 store acts as a release barrier 1.215 + // for current AMD/Intel chips as of Jan 2008. 1.216 + // See also Acquire_Load(), below. 1.217 + 1.218 + // When new chips come out, check: 1.219 + // IA-32 Intel Architecture Software Developer's Manual, Volume 3: 1.220 + // System Programming Guide, Chatper 7: Multiple-processor management, 1.221 + // Section 7.2, Memory Ordering. 1.222 + // Last seen at: 1.223 + // http://developer.intel.com/design/pentium4/manuals/index_new.htm 1.224 + // 1.225 + // x86 stores/loads fail to act as barriers for a few instructions (clflush 1.226 + // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are 1.227 + // not generated by the compiler, and are rare. Users of these instructions 1.228 + // need to know about cache behaviour in any case since all of these involve 1.229 + // either flushing cache lines or non-temporal cache hints. 1.230 +} 1.231 + 1.232 +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { 1.233 + return *ptr; 1.234 +} 1.235 + 1.236 +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { 1.237 + Atomic64 value = *ptr; // An x86 load acts as a acquire barrier, 1.238 + // for current AMD/Intel chips as of Jan 2008. 1.239 + // See also Release_Store(), above. 1.240 + ATOMICOPS_COMPILER_BARRIER(); 1.241 + return value; 1.242 +} 1.243 + 1.244 +inline Atomic64 Release_Load(volatile const Atomic64* ptr) { 1.245 + MemoryBarrier(); 1.246 + return *ptr; 1.247 +} 1.248 + 1.249 +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, 1.250 + Atomic64 old_value, 1.251 + Atomic64 new_value) { 1.252 + Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); 1.253 + if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { 1.254 + __asm__ __volatile__("lfence" : : : "memory"); 1.255 + } 1.256 + return x; 1.257 +} 1.258 + 1.259 +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, 1.260 + Atomic64 old_value, 1.261 + Atomic64 new_value) { 1.262 + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); 1.263 +} 1.264 + 1.265 +#endif // defined(__x86_64__) 1.266 + 1.267 +} // namespace base::subtle 1.268 +} // namespace base 1.269 + 1.270 +#undef ATOMICOPS_COMPILER_BARRIER 1.271 + 1.272 +#endif // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_