1 /* 2 * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef OS_CPU_WINDOWS_X86_ATOMIC_WINDOWS_X86_HPP 26 #define OS_CPU_WINDOWS_X86_ATOMIC_WINDOWS_X86_HPP 27 28 #include "runtime/os.hpp" 29 30 // Note that in MSVC, volatile memory accesses are explicitly 31 // guaranteed to have acquire release semantics (w.r.t. compiler 32 // reordering) and therefore does not even need a compiler barrier 33 // for normal acquire release accesses. And all generalized 34 // bound calls like release_store go through Atomic::load 35 // and Atomic::store which do volatile memory accesses. 36 template<> inline void ScopedFence<X_ACQUIRE>::postfix() { } 37 template<> inline void ScopedFence<RELEASE_X>::prefix() { } 38 template<> inline void ScopedFence<RELEASE_X_FENCE>::prefix() { } 39 template<> inline void ScopedFence<RELEASE_X_FENCE>::postfix() { OrderAccess::fence(); } 40 41 // The following alternative implementations are needed because 42 // Windows 95 doesn't support (some of) the corresponding Windows NT 43 // calls. Furthermore, these versions allow inlining in the caller. 44 // (More precisely: The documentation for InterlockedExchange says 45 // it is supported for Windows 95. However, when single-stepping 46 // through the assembly code we cannot step into the routine and 47 // when looking at the routine address we see only garbage code. 48 // Better safe then sorry!). Was bug 7/31/98 (gri). 49 // 50 // Performance note: On uniprocessors, the 'lock' prefixes are not 51 // necessary (and expensive). We should generate separate cases if 52 // this becomes a performance problem. 53 54 #pragma warning(disable: 4035) // Disables warnings reporting missing return statement 55 56 template<size_t byte_size> 57 struct Atomic::PlatformAdd { 58 template<typename D, typename I> 59 D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const; 60 61 template<typename D, typename I> 62 D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const { 63 return add_and_fetch(dest, add_value, order) - add_value; 64 } 65 }; 66 67 #ifdef AMD64 68 template<> 69 template<typename D, typename I> 70 inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value, 71 atomic_memory_order order) const { 72 return add_using_helper<int32_t>(os::atomic_add_func, dest, add_value); 73 } 74 75 template<> 76 template<typename D, typename I> 77 inline D Atomic::PlatformAdd<8>::add_and_fetch(D volatile* dest, I add_value, 78 atomic_memory_order order) const { 79 return add_using_helper<int64_t>(os::atomic_add_long_func, dest, add_value); 80 } 81 82 #define DEFINE_STUB_XCHG(ByteSize, StubType, StubName) \ 83 template<> \ 84 template<typename T> \ 85 inline T Atomic::PlatformXchg<ByteSize>::operator()(T volatile* dest, \ 86 T exchange_value, \ 87 atomic_memory_order order) const { \ 88 STATIC_ASSERT(ByteSize == sizeof(T)); \ 89 return xchg_using_helper<StubType>(StubName, dest, exchange_value); \ 90 } 91 92 DEFINE_STUB_XCHG(4, int32_t, os::atomic_xchg_func) 93 DEFINE_STUB_XCHG(8, int64_t, os::atomic_xchg_long_func) 94 95 #undef DEFINE_STUB_XCHG 96 97 #define DEFINE_STUB_CMPXCHG(ByteSize, StubType, StubName) \ 98 template<> \ 99 template<typename T> \ 100 inline T Atomic::PlatformCmpxchg<ByteSize>::operator()(T volatile* dest, \ 101 T compare_value, \ 102 T exchange_value, \ 103 atomic_memory_order order) const { \ 104 STATIC_ASSERT(ByteSize == sizeof(T)); \ 105 return cmpxchg_using_helper<StubType>(StubName, dest, compare_value, exchange_value); \ 106 } 107 108 DEFINE_STUB_CMPXCHG(1, int8_t, os::atomic_cmpxchg_byte_func) 109 DEFINE_STUB_CMPXCHG(4, int32_t, os::atomic_cmpxchg_func) 110 DEFINE_STUB_CMPXCHG(8, int64_t, os::atomic_cmpxchg_long_func) 111 112 #undef DEFINE_STUB_CMPXCHG 113 114 #else // !AMD64 115 116 template<> 117 template<typename D, typename I> 118 inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value, 119 atomic_memory_order order) const { 120 STATIC_ASSERT(4 == sizeof(I)); 121 STATIC_ASSERT(4 == sizeof(D)); 122 __asm { 123 mov edx, dest; 124 mov eax, add_value; 125 mov ecx, eax; 126 lock xadd dword ptr [edx], eax; 127 add eax, ecx; 128 } 129 } 130 131 template<> 132 template<typename T> 133 inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, 134 T exchange_value, 135 atomic_memory_order order) const { 136 STATIC_ASSERT(4 == sizeof(T)); 137 // alternative for InterlockedExchange 138 __asm { 139 mov eax, exchange_value; 140 mov ecx, dest; 141 xchg eax, dword ptr [ecx]; 142 } 143 } 144 145 template<> 146 template<typename T> 147 inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest, 148 T compare_value, 149 T exchange_value, 150 atomic_memory_order order) const { 151 STATIC_ASSERT(1 == sizeof(T)); 152 // alternative for InterlockedCompareExchange 153 __asm { 154 mov edx, dest 155 mov cl, exchange_value 156 mov al, compare_value 157 lock cmpxchg byte ptr [edx], cl 158 } 159 } 160 161 template<> 162 template<typename T> 163 inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest, 164 T compare_value, 165 T exchange_value, 166 atomic_memory_order order) const { 167 STATIC_ASSERT(4 == sizeof(T)); 168 // alternative for InterlockedCompareExchange 169 __asm { 170 mov edx, dest 171 mov ecx, exchange_value 172 mov eax, compare_value 173 lock cmpxchg dword ptr [edx], ecx 174 } 175 } 176 177 template<> 178 template<typename T> 179 inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, 180 T compare_value, 181 T exchange_value, 182 atomic_memory_order order) const { 183 STATIC_ASSERT(8 == sizeof(T)); 184 int32_t ex_lo = (int32_t)exchange_value; 185 int32_t ex_hi = *( ((int32_t*)&exchange_value) + 1 ); 186 int32_t cmp_lo = (int32_t)compare_value; 187 int32_t cmp_hi = *( ((int32_t*)&compare_value) + 1 ); 188 __asm { 189 push ebx 190 push edi 191 mov eax, cmp_lo 192 mov edx, cmp_hi 193 mov edi, dest 194 mov ebx, ex_lo 195 mov ecx, ex_hi 196 lock cmpxchg8b qword ptr [edi] 197 pop edi 198 pop ebx 199 } 200 } 201 202 template<> 203 template<typename T> 204 inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { 205 STATIC_ASSERT(8 == sizeof(T)); 206 volatile T dest; 207 volatile T* pdest = &dest; 208 __asm { 209 mov eax, src 210 fild qword ptr [eax] 211 mov eax, pdest 212 fistp qword ptr [eax] 213 } 214 return dest; 215 } 216 217 template<> 218 template<typename T> 219 inline void Atomic::PlatformStore<8>::operator()(T volatile* dest, 220 T store_value) const { 221 STATIC_ASSERT(8 == sizeof(T)); 222 volatile T* src = &store_value; 223 __asm { 224 mov eax, src 225 fild qword ptr [eax] 226 mov eax, dest 227 fistp qword ptr [eax] 228 } 229 } 230 231 #endif // AMD64 232 233 #pragma warning(default: 4035) // Enables warnings reporting missing return statement 234 235 #ifndef AMD64 236 template<> 237 struct Atomic::PlatformOrderedStore<1, RELEASE_X_FENCE> 238 { 239 template <typename T> 240 void operator()(volatile T* p, T v) const { 241 __asm { 242 mov edx, p; 243 mov al, v; 244 xchg al, byte ptr [edx]; 245 } 246 } 247 }; 248 249 template<> 250 struct Atomic::PlatformOrderedStore<2, RELEASE_X_FENCE> 251 { 252 template <typename T> 253 void operator()(volatile T* p, T v) const { 254 __asm { 255 mov edx, p; 256 mov ax, v; 257 xchg ax, word ptr [edx]; 258 } 259 } 260 }; 261 262 template<> 263 struct Atomic::PlatformOrderedStore<4, RELEASE_X_FENCE> 264 { 265 template <typename T> 266 void operator()(volatile T* p, T v) const { 267 __asm { 268 mov edx, p; 269 mov eax, v; 270 xchg eax, dword ptr [edx]; 271 } 272 } 273 }; 274 #endif // AMD64 275 276 #endif // OS_CPU_WINDOWS_X86_ATOMIC_WINDOWS_X86_HPP