1 /* 2 * Copyright (c) 1999, 2017, 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 SHARE_VM_RUNTIME_ATOMIC_HPP 26 #define SHARE_VM_RUNTIME_ATOMIC_HPP 27 28 #include "memory/allocation.hpp" 29 #include "metaprogramming/conditional.hpp" 30 #include "metaprogramming/integerTypes.hpp" 31 #include "metaprogramming/isDerived.hpp" 32 #include "metaprogramming/isIntegral.hpp" 33 #include "metaprogramming/isPointer.hpp" 34 #include "utilities/align.hpp" 35 #include "utilities/debug.hpp" 36 #include "utilities/macros.hpp" 37 38 enum cmpxchg_memory_order { 39 memory_order_relaxed, 40 // Use value which doesn't interfere with C++2011. We need to be more conservative. 41 memory_order_conservative = 8 42 }; 43 44 class GeneralizedAtomic : AllStatic { 45 template<typename T> class Never: public FalseType {}; 46 47 template <typename T> 48 inline static void specialized_store(T store_value, volatile T* dest) { 49 STATIC_ASSERT(sizeof(T) <= size_t(BytesPerWord)); // Does the machine support atomic wide accesses? 50 (void)const_cast<T&>(*dest = store_value); 51 } 52 53 template <typename T> 54 inline static T specialized_load(const volatile T* dest) { 55 STATIC_ASSERT(sizeof(T) <= size_t(BytesPerWord)); // Does the machine support atomic wide accesses? 56 return *dest; 57 } 58 59 template <typename T> 60 inline static T specialized_add(T add_value, volatile T* dest) { 61 STATIC_ASSERT(Never<T>::value); 62 return add_value; 63 } 64 65 template <typename T> 66 inline static void specialized_inc(volatile T* dest) { 67 add(1, dest); 68 } 69 70 template <typename T> 71 inline static void specialized_dec(volatile T* dest) { 72 add(-1, dest); 73 } 74 75 template <typename T> 76 inline static T specialized_xchg(T exchange_value, volatile T* dest) { 77 STATIC_ASSERT(Never<T>::value); 78 return exchange_value; 79 } 80 81 template <typename T> 82 inline static T specialized_cmpxchg(T exchange_value, volatile T* dest, T compare_value, cmpxchg_memory_order order) { 83 STATIC_ASSERT(Never<T>::value); 84 return exchange_value; 85 } 86 87 public: 88 template <typename T, typename U> 89 inline static void store(T store_value, volatile U* dest); 90 91 template <typename T> 92 inline static T load(volatile T* src); 93 94 template <typename T, typename U> 95 inline static U add(T add_value, volatile U* dst); 96 97 template <typename T, typename U> 98 inline static U* add(T add_value, U* volatile* dst); 99 100 template <typename T> 101 inline static void inc(volatile T* dest); 102 103 template <typename T> 104 inline static void inc(T* volatile* dest); 105 106 template <typename T> 107 inline static void dec(volatile T* dest); 108 109 template <typename T> 110 inline static void dec(T* volatile* dest); 111 112 template <typename T, typename U> 113 inline static U xchg(T exchange_value, volatile U* dest); 114 115 template <typename T, typename U, typename V> 116 inline static U cmpxchg(T exchange_value, volatile U* dest, V compare_value, cmpxchg_memory_order order); 117 }; 118 119 120 // platform specific in-line definitions - must come before shared definitions 121 122 class PlatformAtomic; 123 124 #include OS_CPU_HEADER(atomic) 125 126 typedef Conditional<IsDerived<PlatformAtomic, AllStatic>::value, PlatformAtomic, GeneralizedAtomic>::type AtomicImpl; 127 128 class Atomic : AllStatic { 129 public: 130 // Atomic operations on 64-bit types are not available on all 32-bit 131 // platforms. If atomic ops on 64-bit types are defined here they must only 132 // be used from code that verifies they are available at runtime and 133 // can provide an alternative action if not - see supports_cx8() for 134 // a means to test availability. 135 136 // The memory operations that are mentioned with each of the atomic 137 // function families come from src/share/vm/runtime/orderAccess.hpp, 138 // e.g., <fence> is described in that file and is implemented by the 139 // OrderAccess::fence() function. See that file for the gory details 140 // on the Memory Access Ordering Model. 141 142 // All of the atomic operations that imply a read-modify-write action 143 // guarantee a two-way memory barrier across that operation. Historically 144 // these semantics reflect the strength of atomic operations that are 145 // provided on SPARC/X86. We assume that strength is necessary unless 146 // we can prove that a weaker form is sufficiently safe. 147 148 // Atomically store to a location 149 // See comment above about using 64-bit atomics on 32-bit platforms 150 template <typename T, typename U> 151 inline static void store(T store_value, volatile U* dest); 152 153 // The store_ptr() member functions are deprecated. Use store() instead. 154 static void store_ptr(intptr_t store_value, volatile intptr_t* dest) { 155 store(store_value, dest); 156 } 157 158 static void store_ptr(void* store_value, volatile void* dest) { 159 store((intptr_t)store_value, (volatile intptr_t*)dest); 160 } 161 162 // Atomically load from a location 163 // See comment above about using 64-bit atomics on 32-bit platforms 164 template <typename T> 165 inline static T load(volatile T* src); 166 167 // Atomically add to a location. Returns updated value. add*() provide: 168 // <fence> add-value-to-dest <membar StoreLoad|StoreStore> 169 // add(I1 v, I* d) 170 // add(I1 v, P* d) 171 // where I, I1 are integral types, P is a pointer type. 172 // Functional behavior is modelled on *dest += add_value. 173 template <typename T, typename U> 174 inline static U add(T add_value, volatile U* dst); 175 176 // The add_ptr() member functions are deprecated. Use add() instead. 177 static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest) { 178 return add(add_value, dest); 179 } 180 181 static void* add_ptr(intptr_t add_value, volatile void* dest) { 182 return (void*)add(add_value, (volatile intptr_t*)dest); 183 } 184 185 // Atomically increment location. inc*() provide: 186 // <fence> increment-dest <membar StoreLoad|StoreStore> 187 // Functional behavior is modelled on *dest++ 188 template <typename T> 189 inline static void inc(volatile T* dest); 190 191 // The inc_ptr member functions are deprecated. Use inc() instead. 192 static void inc_ptr(volatile intptr_t* dest) { 193 inc(dest); 194 } 195 196 static void inc_ptr(volatile void* dest) { 197 inc((volatile intptr_t*)dest); 198 } 199 200 // Atomically decrement a location. dec*() provide: 201 // <fence> decrement-dest <membar StoreLoad|StoreStore> 202 // Functional behavior is modelled on *dest-- 203 template <typename T> 204 inline static void dec(volatile T* dest); 205 206 // The dec_ptr member functions are deprecated. Use dec() instead. 207 static void dec_ptr(volatile intptr_t* dest) { 208 dec(dest); 209 } 210 211 static void dec_ptr(volatile void* dest) { 212 dec((volatile intptr_t*)dest); 213 } 214 215 // Performs atomic exchange of *dest with exchange_value. Returns old 216 // prior value of *dest. xchg*() provide: 217 // <fence> exchange-value-with-dest <membar StoreLoad|StoreStore> 218 template <typename T, typename U> 219 inline static U xchg(T exchange_value, volatile U* dest); 220 221 // The xchg_ptr() member functions are deprecated. Use xchg() instead. 222 static intptr_t xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { 223 return xchg(exchange_value, dest); 224 } 225 226 static void* xchg_ptr(void* exchange_value, volatile void* dest) { 227 return (void*)xchg((intptr_t)exchange_value, (volatile intptr_t*)dest); 228 } 229 230 // Performs atomic compare of *dest and compare_value, and exchanges 231 // *dest with exchange_value if the comparison succeeded. Returns prior 232 // value of *dest. cmpxchg*() provide: 233 // <fence> compare-and-exchange <membar StoreLoad|StoreStore> 234 // See comment above about using 64-bit atomics on 32-bit platforms 235 template <typename T, typename U, typename V> 236 inline static U cmpxchg(T exchange_value, volatile U* dest, V compare_value, cmpxchg_memory_order order = memory_order_conservative); 237 238 // The cmpxchg_ptr member functions are deprecated. Use cmpxchg() instead. 239 inline static intptr_t cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, 240 intptr_t compare_value, cmpxchg_memory_order order = memory_order_conservative) { 241 return cmpxchg(exchange_value, dest, compare_value, order); 242 } 243 244 inline static void* cmpxchg_ptr(void* exchange_value, volatile void* dest, 245 void* compare_value, cmpxchg_memory_order order = memory_order_conservative) { 246 return (void*)cmpxchg((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order); 247 } 248 }; 249 250 // internal implementation 251 252 template <typename T, typename U> 253 inline void GeneralizedAtomic::store(T store_value, volatile U* dest) { 254 typedef typename IntegerTypes::Signed<U>::type Raw; 255 U store_value_cast = store_value; 256 specialized_store(IntegerTypes::cast_to_signed(store_value_cast), reinterpret_cast<volatile Raw*>(dest)); 257 } 258 259 template <typename T> 260 inline T GeneralizedAtomic::load(volatile T* src) { 261 typedef typename IntegerTypes::Signed<T>::type Raw; 262 return IntegerTypes::cast<T>(specialized_load(reinterpret_cast<const volatile Raw*>(src))); 263 } 264 265 template <typename T, typename U> 266 inline U GeneralizedAtomic::add(T add_value, volatile U* dst) { 267 STATIC_ASSERT(IsIntegral<T>::value); 268 STATIC_ASSERT(IsIntegral<U>::value); 269 typedef typename IntegerTypes::Signed<U>::type Raw; 270 // Allow -Wconversion or the like to complain about unsafe conversions. 271 U value = add_value; 272 Raw raw_value = IntegerTypes::cast_to_signed(value); 273 Raw result = specialized_add(raw_value, reinterpret_cast<volatile Raw*>(dst)); 274 return IntegerTypes::cast<U>(result); 275 } 276 277 template <typename T, typename U> 278 inline U* GeneralizedAtomic::add(T add_value, U* volatile* dst) { 279 STATIC_ASSERT(IsIntegral<T>::value); 280 typedef typename IntegerTypes::Signed<U*>::type Raw; 281 ptrdiff_t value = add_value; 282 Raw raw_value = IntegerTypes::cast_to_signed(value * sizeof(U)); 283 Raw result = specialized_add(raw_value, reinterpret_cast<volatile Raw*>(dst)); 284 return IntegerTypes::cast<U*>(result); 285 } 286 287 template <typename T> 288 inline void GeneralizedAtomic::inc(volatile T* src) { 289 STATIC_ASSERT(IsIntegral<T>::value); 290 typedef typename IntegerTypes::Signed<T>::type Raw; 291 specialized_inc(reinterpret_cast<volatile Raw*>(src)); 292 } 293 294 template <typename T> 295 inline void GeneralizedAtomic::inc(T* volatile* src) { 296 if (sizeof(T) != 1) { 297 add(1, src); 298 } else { 299 typedef typename IntegerTypes::Signed<T*>::type Raw; 300 specialized_inc(reinterpret_cast<volatile Raw*>(src)); 301 } 302 } 303 304 template <typename T> 305 inline void GeneralizedAtomic::dec(volatile T* src) { 306 STATIC_ASSERT(IsIntegral<T>::value); 307 typedef typename IntegerTypes::Signed<T>::type Raw; 308 specialized_dec(reinterpret_cast<volatile Raw*>(src)); 309 } 310 311 template <typename T> 312 inline void GeneralizedAtomic::dec(T* volatile* src) { 313 if (sizeof(T) != 1) { 314 add(-1, src); 315 } else { 316 typedef typename IntegerTypes::Signed<T*>::type Raw; 317 specialized_dec(reinterpret_cast<volatile Raw*>(src)); 318 } 319 } 320 321 template <typename T, typename U> 322 inline U GeneralizedAtomic::xchg(T exchange_value, volatile U* dest) { 323 typedef typename IntegerTypes::Signed<U>::type Raw; 324 U exchange_value_cast = exchange_value; 325 Raw result = specialized_xchg(IntegerTypes::cast_to_signed(exchange_value_cast), 326 reinterpret_cast<volatile Raw*>(dest)); 327 return IntegerTypes::cast<U>(result); 328 } 329 330 template <typename T, typename U, typename V> 331 inline U GeneralizedAtomic::cmpxchg(T exchange_value, volatile U* dest, V compare_value, cmpxchg_memory_order order) { 332 typedef typename IntegerTypes::Signed<U>::type Raw; 333 U exchange_value_cast = exchange_value; 334 U compare_value_cast = compare_value; 335 Raw result = specialized_cmpxchg(IntegerTypes::cast_to_signed(exchange_value_cast), 336 reinterpret_cast<volatile Raw*>(dest), 337 IntegerTypes::cast_to_signed(compare_value_cast), order); 338 return IntegerTypes::cast<U>(result); 339 } 340 341 template <typename T, typename U> 342 inline void Atomic::store(T store_value, volatile U* dest) { 343 AtomicImpl::store(store_value, dest); 344 } 345 346 template <typename T> 347 inline T Atomic::load(volatile T* src) { 348 return AtomicImpl::load(src); 349 } 350 351 template <typename T, typename U> 352 inline U Atomic::add(T add_value, volatile U* dst) { 353 return AtomicImpl::add(add_value, dst); 354 } 355 356 template <typename T> 357 inline void Atomic::inc(volatile T* src) { 358 AtomicImpl::inc(src); 359 } 360 361 template <typename T> 362 inline void Atomic::dec(volatile T* src) { 363 AtomicImpl::dec(src); 364 } 365 366 template <typename T, typename U> 367 inline U Atomic::xchg(T exchange_value, volatile U* dest) { 368 return AtomicImpl::xchg(exchange_value, dest); 369 } 370 371 template <typename T, typename U, typename V> 372 inline U Atomic::cmpxchg(T exchange_value, volatile U* dest, V compare_value, cmpxchg_memory_order order) { 373 return AtomicImpl::cmpxchg(exchange_value, dest, compare_value, order); 374 } 375 376 // shared in-line definitions 377 378 #ifndef VM_HAS_SPECIALIZED_CMPXCHG_BYTE 379 /* 380 * This is the default implementation of byte-sized cmpxchg. It emulates 8-bit-sized cmpxchg 381 * in terms of 32-bit-sized cmpxchg. Platforms may override this by defining their own inline definition 382 * as well as defining VM_HAS_SPECIALIZED_CMPXCHG_BYTE. This will cause the platform specific 383 * implementation to be used instead. 384 */ 385 template <> 386 inline int8_t GeneralizedAtomic::specialized_cmpxchg<int8_t>(int8_t exchange_value, volatile int8_t* dest, 387 int8_t compare_value, cmpxchg_memory_order order) { 388 volatile int32_t* dest_int = 389 reinterpret_cast<volatile int32_t*>(align_down(dest, sizeof(int32_t))); 390 size_t offset = pointer_delta(dest, dest_int, 1); 391 int32_t cur = *dest_int; 392 int8_t* cur_as_bytes = reinterpret_cast<int8_t*>(&cur); 393 394 // current value may not be what we are looking for, so force it 395 // to that value so the initial cmpxchg will fail if it is different 396 cur_as_bytes[offset] = compare_value; 397 398 // always execute a real cmpxchg so that we get the required memory 399 // barriers even on initial failure 400 do { 401 // value to swap in matches current value ... 402 int32_t new_value = cur; 403 // ... except for the one byte we want to update 404 reinterpret_cast<int8_t*>(&new_value)[offset] = exchange_value; 405 406 int32_t res = cmpxchg(new_value, dest_int, cur, order); 407 if (res == cur) break; // success 408 409 // at least one byte in the int changed value, so update 410 // our view of the current int 411 cur = res; 412 // if our byte is still as cur we loop and try again 413 } while (cur_as_bytes[offset] == compare_value); 414 415 return cur_as_bytes[offset]; 416 } 417 418 #endif // VM_HAS_SPECIALIZED_CMPXCHG_BYTE 419 420 template <> 421 inline int16_t GeneralizedAtomic::specialized_add<int16_t>(int16_t add_value, volatile int16_t* dest) { 422 // Most platforms do not support atomic add on a 2-byte value. However, 423 // if the value occupies the most significant 16 bits of an aligned 32-bit 424 // word, then we can do this with an atomic add of (add_value << 16) 425 // to the 32-bit word. 426 // 427 // The least significant parts of this 32-bit word will never be affected, even 428 // in case of overflow/underflow. 429 // 430 // Use the ATOMIC_SHORT_PAIR macro (see macros.hpp) to get the desired alignment. 431 #ifdef VM_LITTLE_ENDIAN 432 assert((intx(dest) & 0x03) == 0x02, "wrong alignment"); 433 int32_t new_value = Atomic::add(int32_t(add_value) << 16, (volatile int32_t*)(dest-1)); 434 #else 435 assert((intx(dest) & 0x03) == 0x00, "wrong alignment"); 436 int32_t new_value = Atomic::add(int32_t(add_value) << 16, (volatile int32_t*)(dest)); 437 #endif 438 return (int16_t)(new_value >> 16); // preserves sign 439 } 440 441 template <> 442 inline void GeneralizedAtomic::specialized_inc<int16_t>(volatile int16_t* dest) { 443 (void)add(int16_t(1), dest); 444 } 445 446 template <> 447 inline void GeneralizedAtomic::specialized_dec<int16_t>(volatile int16_t* dest) { 448 (void)add(int16_t(-1), dest); 449 } 450 451 #endif // SHARE_VM_RUNTIME_ATOMIC_HPP