--- old/src/os/bsd/vm/os_bsd.cpp 2017-08-16 01:19:02.461913954 -0400 +++ new/src/os/bsd/vm/os_bsd.cpp 2017-08-16 01:19:02.345908007 -0400 @@ -952,7 +952,7 @@ if (now <= prev) { return prev; // same or retrograde time; } - const uint64_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&Bsd::_max_abstime, prev); + const uint64_t obsv = Atomic::cmpxchg(now, &Bsd::_max_abstime, prev); assert(obsv >= prev, "invariant"); // Monotonicity // If the CAS succeeded then we're done and return "now". // If the CAS failed and the observed value "obsv" is >= now then --- old/src/os/solaris/vm/os_solaris.cpp 2017-08-16 01:19:03.041943704 -0400 +++ new/src/os/solaris/vm/os_solaris.cpp 2017-08-16 01:19:02.925937756 -0400 @@ -1197,7 +1197,7 @@ if (now <= prev) { return prev; // same or retrograde time; } - const hrtime_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&max_hrtime, prev); + const hrtime_t obsv = Atomic::cmpxchg(now, &max_hrtime, prev); assert(obsv >= prev, "invariant"); // Monotonicity // If the CAS succeeded then we're done and return "now". // If the CAS failed and the observed value "obsv" is >= now then --- old/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.hpp 2017-08-16 01:19:03.633974066 -0400 +++ new/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.hpp 2017-08-16 01:19:03.521968317 -0400 @@ -306,8 +306,13 @@ } } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_CAST(1 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not @@ -368,16 +373,22 @@ cmpxchg_post_membar(order); - return (jbyte)(unsigned char)old_value; + return IntegerTypes::cast((unsigned char)old_value); } -inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_CAST(4 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not // specified otherwise (see atomic.hpp). - unsigned int old_value; + T old_value; const uint64_t zero = 0; cmpxchg_pre_membar(order); @@ -412,16 +423,22 @@ cmpxchg_post_membar(order); - return (jint) old_value; + return old_value; } -inline jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_CAST(8 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not // specified otherwise (see atomic.hpp). - long old_value; + T old_value; const uint64_t zero = 0; cmpxchg_pre_membar(order); @@ -456,15 +473,7 @@ cmpxchg_post_membar(order); - return (jlong) old_value; -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); + return old_value; } #undef strasm_sync --- old/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.hpp 2017-08-16 01:19:04.170001561 -0400 +++ new/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.hpp 2017-08-16 01:19:04.057995828 -0400 @@ -25,8 +25,6 @@ #ifndef OS_CPU_BSD_X86_VM_ATOMIC_BSD_X86_HPP #define OS_CPU_BSD_X86_VM_ATOMIC_BSD_X86_HPP -#include "runtime/os.hpp" - // Implementation of class atomic inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } @@ -81,8 +79,13 @@ return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(1 == sizeof(T)); __asm__ volatile ( "lock cmpxchgb %1,(%3)" : "=a" (exchange_value) : "q" (exchange_value), "a" (compare_value), "r" (dest) @@ -90,7 +93,13 @@ return exchange_value; } -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(4 == sizeof(T)); __asm__ volatile ( "lock cmpxchgl %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) @@ -137,7 +146,13 @@ return exchange_value; } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(8 == sizeof(T)); __asm__ __volatile__ ( "lock cmpxchgq %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) @@ -145,14 +160,6 @@ return exchange_value; } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - inline jlong Atomic::load(const volatile jlong* src) { return *src; } #else // !AMD64 @@ -184,16 +191,14 @@ void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst); } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg_long(exchange_value, dest, compare_value, os::is_MP()); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); + return cmpxchg_using_helper(_Atomic_cmpxchg_long, exchange_value, dest, compare_value); } inline jlong Atomic::load(const volatile jlong* src) { --- old/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.hpp 2017-08-16 01:19:04.710029260 -0400 +++ new/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.hpp 2017-08-16 01:19:04.598023513 -0400 @@ -57,9 +57,9 @@ /* Perform an atomic compare and swap: if the current value of `*PTR' is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of `*PTR' before the operation.*/ -static inline int m68k_compare_and_swap(volatile int *ptr, - int oldval, - int newval) { +static inline int m68k_compare_and_swap(int newval, + volatile int *ptr, + int oldval) { for (;;) { int prev = *ptr; if (prev != oldval) @@ -118,9 +118,9 @@ /* Perform an atomic compare and swap: if the current value of `*PTR' is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of `*PTR' before the operation.*/ -static inline int arm_compare_and_swap(volatile int *ptr, - int oldval, - int newval) { +static inline int arm_compare_and_swap(int newval, + volatile int *ptr, + int oldval) { for (;;) { int prev = *ptr; if (prev != oldval) @@ -267,53 +267,36 @@ (volatile intptr_t*) dest); } -inline jint Atomic::cmpxchg(jint exchange_value, - volatile jint* dest, - jint compare_value, - cmpxchg_memory_order order) { +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) { + STATIC_CAST(4 == sizeof(T)); #ifdef ARM - return arm_compare_and_swap(dest, compare_value, exchange_value); + return cmpxchg_using_helper(arm_compare_and_swap, exchange_value, dest, compare_value); #else #ifdef M68K - return m68k_compare_and_swap(dest, compare_value, exchange_value); + return cmpxchg_using_helper(m68k_compare_and_swap, exchange_value, dest, compare_value); #else return __sync_val_compare_and_swap(dest, compare_value, exchange_value); #endif // M68K #endif // ARM } -inline jlong Atomic::cmpxchg(jlong exchange_value, - volatile jlong* dest, - jlong compare_value, - cmpxchg_memory_order order) { - - return __sync_val_compare_and_swap(dest, compare_value, exchange_value); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, - volatile intptr_t* dest, - intptr_t compare_value, - cmpxchg_memory_order order) { -#ifdef ARM - return arm_compare_and_swap(dest, compare_value, exchange_value); -#else -#ifdef M68K - return m68k_compare_and_swap(dest, compare_value, exchange_value); -#else +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) { + STATIC_CAST(8 == sizeof(T)); return __sync_val_compare_and_swap(dest, compare_value, exchange_value); -#endif // M68K -#endif // ARM -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, - volatile void* dest, - void* compare_value, - cmpxchg_memory_order order) { - - return (void *) cmpxchg_ptr((intptr_t) exchange_value, - (volatile intptr_t*) dest, - (intptr_t) compare_value, - order); } inline jlong Atomic::load(const volatile jlong* src) { --- old/src/os_cpu/linux_aarch64/vm/atomic_linux_aarch64.hpp 2017-08-16 01:19:05.246056752 -0400 +++ new/src/os_cpu/linux_aarch64/vm/atomic_linux_aarch64.hpp 2017-08-16 01:19:05.138051207 -0400 @@ -85,9 +85,13 @@ (volatile intptr_t*) dest); } -template T generic_cmpxchg(T exchange_value, volatile T* dest, - T compare_value, cmpxchg_memory_order order) -{ +template +template +inline T Atomic::PlatformCmpxchg::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order) const { + STATIC_ASSERT(byte_size == sizeof(T)); if (order == memory_order_relaxed) { T value = compare_value; __atomic_compare_exchange(dest, &value, &exchange_value, /*weak*/false, @@ -98,17 +102,6 @@ } } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) -{ - return generic_cmpxchg(exchange_value, dest, compare_value, order); -} - -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) -{ - return generic_cmpxchg(exchange_value, dest, compare_value, order); -} - inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } @@ -139,24 +132,6 @@ return res; } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) -{ - return generic_cmpxchg(exchange_value, dest, compare_value, order); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) -{ - return generic_cmpxchg(exchange_value, dest, compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) -{ - return (void *) cmpxchg_ptr((intptr_t) exchange_value, - (volatile intptr_t*) dest, - (intptr_t) compare_value, - order); -} - inline jlong Atomic::load(const volatile jlong* src) { return *src; } #endif // OS_CPU_LINUX_AARCH64_VM_ATOMIC_LINUX_AARCH64_HPP --- old/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp 2017-08-16 01:19:05.774083831 -0400 +++ new/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp 2017-08-16 01:19:05.662078089 -0400 @@ -200,9 +200,38 @@ // The memory_order parameter is ignored - we always provide the strongest/most-conservative ordering -inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +#ifndef AARCH64 + +inline jint reorder_cmpxchg_func(jint exchange_value, + jint volatile* dest, + jint compare_value) { + // Warning: Arguments are swapped to avoid moving them for kernel call + return (*os::atomic_cmpxchg_func)(compare_value, exchange_value, dest); +} + +inline jlong reorder_cmpxchg_long_func(jlong exchange_value, + jlong volatile* dest, + jlong compare_value) { + assert(VM_Version::supports_cx8(), "Atomic compare and exchange jlong not supported on this architecture!"); + // Warning: Arguments are swapped to avoid moving them for kernel call + return (*os::atomic_cmpxchg_long_func)(compare_value, exchange_value, dest); +} + +#endif // !AARCH64 + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); #ifdef AARCH64 - jint rv; + T rv; int tmp; __asm__ volatile( "1:\n\t" @@ -220,14 +249,19 @@ : "memory"); return rv; #else - // Warning: Arguments are swapped to avoid moving them for kernel call - return (*os::atomic_cmpxchg_func)(compare_value, exchange_value, dest); + return cmpxchg_using_helper(reorder_cmpxchg_func, exchange_value, dest, compare_value); #endif } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); #ifdef AARCH64 - jlong rv; + T rv; int tmp; __asm__ volatile( "1:\n\t" @@ -245,21 +279,8 @@ : "memory"); return rv; #else - assert(VM_Version::supports_cx8(), "Atomic compare and exchange jlong not supported on this architecture!"); - return (*os::atomic_cmpxchg_long_func)(compare_value, exchange_value, dest); -#endif -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { -#ifdef AARCH64 - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -#else - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); + return cmpxchg_using_helper(reorder_cmpxchg_long_func, exchange_value, dest, compare_value); #endif } -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order); -} - #endif // OS_CPU_LINUX_ARM_VM_ATOMIC_LINUX_ARM_HPP --- old/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.hpp 2017-08-16 01:19:06.310111322 -0400 +++ new/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.hpp 2017-08-16 01:19:06.198105576 -0400 @@ -306,8 +306,13 @@ } } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(1 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not @@ -368,16 +373,22 @@ cmpxchg_post_membar(order); - return (jbyte)(unsigned char)old_value; + return IntegerTypes::cast((unsigned char)old_value); } -inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not // specified otherwise (see atomic.hpp). - unsigned int old_value; + T old_value; const uint64_t zero = 0; cmpxchg_pre_membar(order); @@ -412,16 +423,22 @@ cmpxchg_post_membar(order); - return (jint) old_value; + return old_value; } -inline jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not // specified otherwise (see atomic.hpp). - long old_value; + T old_value; const uint64_t zero = 0; cmpxchg_pre_membar(order); @@ -456,15 +473,7 @@ cmpxchg_post_membar(order); - return (jlong) old_value; -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); + return old_value; } #undef strasm_sync --- old/src/os_cpu/linux_s390/vm/atomic_linux_s390.hpp 2017-08-16 01:19:06.866139847 -0400 +++ new/src/os_cpu/linux_s390/vm/atomic_linux_s390.hpp 2017-08-16 01:19:06.758134301 -0400 @@ -478,7 +478,17 @@ // function is performed before the operand is fetched and again after the // operation is completed." -jint Atomic::cmpxchg(jint xchg_val, volatile jint* dest, jint cmp_val, cmpxchg_memory_order unused) { +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T xchg_val, + T volatile* dest, + T cmp_val, + cmpxchg_memory_order unused) const { + STATIC_ASSERT(4 == sizeof(T)); unsigned long old; __asm__ __volatile__ ( @@ -493,11 +503,17 @@ : "cc" ); - return (jint)old; + return IntegerTypes::cast((uint32_t)old); } -jlong Atomic::cmpxchg(jlong xchg_val, volatile jlong* dest, jlong cmp_val, cmpxchg_memory_order unused) { - unsigned long old; +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T xchg_val, + T volatile* dest, + T cmp_val, + cmpxchg_memory_order unused) const { + STATIC_ASSERT(8 == sizeof(T)); + T old; __asm__ __volatile__ ( " CSG %[old],%[upd],%[mem] \n\t" // Try to xchg upd with mem. @@ -511,15 +527,7 @@ : "cc" ); - return (jlong)old; -} - -void* Atomic::cmpxchg_ptr(void *xchg_val, volatile void* dest, void* cmp_val, cmpxchg_memory_order unused) { - return (void*)cmpxchg((jlong)xchg_val, (volatile jlong*)dest, (jlong)cmp_val, unused); -} - -intptr_t Atomic::cmpxchg_ptr(intptr_t xchg_val, volatile intptr_t* dest, intptr_t cmp_val, cmpxchg_memory_order unused) { - return (intptr_t)cmpxchg((jlong)xchg_val, (volatile jlong*)dest, (jlong)cmp_val, unused); + return old; } inline jlong Atomic::load(const volatile jlong* src) { return *src; } --- old/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp 2017-08-16 01:19:07.398167127 -0400 +++ new/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp 2017-08-16 01:19:07.290161588 -0400 @@ -121,9 +121,18 @@ return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } - -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { - jint rv; +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) { + STATIC_ASSERT(4 == sizeof(T)); + T rv; __asm__ volatile( " cas [%2], %3, %0" : "=r" (rv) @@ -132,8 +141,14 @@ return rv; } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - jlong rv; +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) { + STATIC_ASSERT(8 == sizeof(T)); + T rv; __asm__ volatile( " casx [%2], %3, %0" : "=r" (rv) @@ -142,18 +157,4 @@ return rv; } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - intptr_t rv; - __asm__ volatile( - " casx [%2], %3, %0" - : "=r" (rv) - : "0" (exchange_value), "r" (dest), "r" (compare_value) - : "memory"); - return rv; -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order); -} - #endif // OS_CPU_LINUX_SPARC_VM_ATOMIC_LINUX_SPARC_INLINE_HPP --- old/src/os_cpu/linux_x86/vm/atomic_linux_x86.hpp 2017-08-16 01:19:07.934194619 -0400 +++ new/src/os_cpu/linux_x86/vm/atomic_linux_x86.hpp 2017-08-16 01:19:07.822188872 -0400 @@ -25,8 +25,6 @@ #ifndef OS_CPU_LINUX_X86_VM_ATOMIC_LINUX_X86_HPP #define OS_CPU_LINUX_X86_VM_ATOMIC_LINUX_X86_HPP -#include "runtime/os.hpp" - // Implementation of class atomic inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } @@ -81,8 +79,13 @@ return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(1 == sizeof(T)); __asm__ volatile ("lock cmpxchgb %1,(%3)" : "=a" (exchange_value) : "q" (exchange_value), "a" (compare_value), "r" (dest) @@ -90,7 +93,13 @@ return exchange_value; } -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(4 == sizeof(T)); __asm__ volatile ("lock cmpxchgl %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) @@ -137,7 +146,13 @@ return exchange_value; } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(8 == sizeof(T)); __asm__ __volatile__ ("lock cmpxchgq %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) @@ -145,14 +160,6 @@ return exchange_value; } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - inline jlong Atomic::load(const volatile jlong* src) { return *src; } #else // !AMD64 @@ -184,16 +191,14 @@ void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst); } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg_long(exchange_value, dest, compare_value); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); + return cmpxchg_using_helper(_Atomic_cmpxchg_long, exchange_value, dest, compare_value); } inline jlong Atomic::load(const volatile jlong* src) { --- old/src/os_cpu/linux_zero/vm/atomic_linux_zero.hpp 2017-08-16 01:19:08.470222111 -0400 +++ new/src/os_cpu/linux_zero/vm/atomic_linux_zero.hpp 2017-08-16 01:19:08.358216364 -0400 @@ -57,9 +57,9 @@ /* Perform an atomic compare and swap: if the current value of `*PTR' is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of `*PTR' before the operation.*/ -static inline int m68k_compare_and_swap(volatile int *ptr, - int oldval, - int newval) { +static inline int m68k_compare_and_swap(int newval, + volatile int *ptr, + int oldval) { for (;;) { int prev = *ptr; if (prev != oldval) @@ -118,9 +118,9 @@ /* Perform an atomic compare and swap: if the current value of `*PTR' is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of `*PTR' before the operation.*/ -static inline int arm_compare_and_swap(volatile int *ptr, - int oldval, - int newval) { +static inline int arm_compare_and_swap(int newval, + volatile int *ptr, + int oldval) { for (;;) { int prev = *ptr; if (prev != oldval) @@ -261,53 +261,36 @@ (volatile intptr_t*) dest); } -inline jint Atomic::cmpxchg(jint exchange_value, - volatile jint* dest, - jint compare_value, - cmpxchg_memory_order order) { +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) { + STATIC_ASSERT(4 == sizeof(T)); #ifdef ARM - return arm_compare_and_swap(dest, compare_value, exchange_value); + return cmpxchg_using_helper(arm_compare_and_swap, exchange_value, dest, compare_value); #else #ifdef M68K - return m68k_compare_and_swap(dest, compare_value, exchange_value); + return cmpxchg_using_helper(m68k_compare_and_swap, exchange_value, dest, compare_value); #else return __sync_val_compare_and_swap(dest, compare_value, exchange_value); #endif // M68K #endif // ARM } -inline jlong Atomic::cmpxchg(jlong exchange_value, - volatile jlong* dest, - jlong compare_value, - cmpxchg_memory_order order) { - - return __sync_val_compare_and_swap(dest, compare_value, exchange_value); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, - volatile intptr_t* dest, - intptr_t compare_value, - cmpxchg_memory_order order) { -#ifdef ARM - return arm_compare_and_swap(dest, compare_value, exchange_value); -#else -#ifdef M68K - return m68k_compare_and_swap(dest, compare_value, exchange_value); -#else +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) { + STATIC_ASSERT(8 == sizeof(T)); return __sync_val_compare_and_swap(dest, compare_value, exchange_value); -#endif // M68K -#endif // ARM -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, - volatile void* dest, - void* compare_value, - cmpxchg_memory_order order) { - - return (void *) cmpxchg_ptr((intptr_t) exchange_value, - (volatile intptr_t*) dest, - (intptr_t) compare_value, - order); } inline jlong Atomic::load(const volatile jlong* src) { --- old/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.hpp 2017-08-16 01:19:09.010249808 -0400 +++ new/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.hpp 2017-08-16 01:19:08.898244060 -0400 @@ -25,8 +25,6 @@ #ifndef OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_HPP #define OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_HPP -#include "runtime/os.hpp" - // Implementation of class atomic inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } @@ -64,10 +62,6 @@ extern "C" jint _Atomic_swap32(jint exchange_value, volatile jint* dest); extern "C" intptr_t _Atomic_swap64(intptr_t exchange_value, volatile intptr_t* dest); -extern "C" jint _Atomic_cas32(jint exchange_value, volatile jint* dest, jint compare_value); -extern "C" intptr_t _Atomic_cas64(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value); -extern "C" jlong _Atomic_casl (jlong exchange_value, volatile jlong* dest, jlong compare_value); - extern "C" jint _Atomic_add32(jint inc, volatile jint* dest); extern "C" intptr_t _Atomic_add64(intptr_t add_value, volatile intptr_t* dest); @@ -97,22 +91,40 @@ return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } - -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { - return _Atomic_cas32(exchange_value, dest, compare_value); -} - -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - // Return 64 bit value in %o0 - return _Atomic_cas64((intptr_t)exchange_value, (intptr_t *)dest, (intptr_t)compare_value); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return _Atomic_cas64(exchange_value, dest, compare_value); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order); +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); + T rv; + __asm__ volatile( + " cas [%2], %3, %0" + : "=r" (rv) + : "0" (exchange_value), "r" (dest), "r" (compare_value) + : "memory"); + return rv; +} + +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); + T rv; + __asm__ volatile( + " casx [%2], %3, %0" + : "=r" (rv) + : "0" (exchange_value), "r" (dest), "r" (compare_value) + : "memory"); + return rv; } #endif // OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_HPP --- old/src/os_cpu/solaris_sparc/vm/solaris_sparc.il 2017-08-16 01:19:09.542277093 -0400 +++ new/src/os_cpu/solaris_sparc/vm/solaris_sparc.il 2017-08-16 01:19:09.430271355 -0400 @@ -73,74 +73,6 @@ .end - // Support for jint Atomic::cmpxchg(jint exchange_value, - // volatile jint* dest, - // jint compare_value) - // - // Arguments: - // exchange_value: O0 - // dest: O1 - // compare_value: O2 - // - // Results: - // O0: the value previously stored in dest - - .inline _Atomic_cas32, 3 - .volatile - cas [%o1], %o2, %o0 - .nonvolatile - .end - - - // Support for intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, - // volatile intptr_t* dest, - // intptr_t compare_value) - // - // 64-bit - // - // Arguments: - // exchange_value: O0 - // dest: O1 - // compare_value: O2 - // - // Results: - // O0: the value previously stored in dest - - .inline _Atomic_cas64, 3 - .volatile - casx [%o1], %o2, %o0 - .nonvolatile - .end - - - // Support for jlong Atomic::cmpxchg(jlong exchange_value, - // volatile jlong* dest, - // jlong compare_value) - // - // 32-bit calling conventions - // - // Arguments: - // exchange_value: O1:O0 - // dest: O2 - // compare_value: O4:O3 - // - // Results: - // O1:O0: the value previously stored in dest - - .inline _Atomic_casl, 3 - .volatile - sllx %o0, 32, %o0 - srl %o1, 0, %o1 - or %o0,%o1,%o0 - sllx %o3, 32, %o3 - srl %o4, 0, %o4 - or %o3,%o4,%o3 - casx [%o2], %o3, %o0 - srl %o0, 0, %o1 - srlx %o0, 32, %o0 - .nonvolatile - .end - // Support for jlong Atomic::load and Atomic::store on v9. // // void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst) --- old/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.hpp 2017-08-16 01:19:10.074304387 -0400 +++ new/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.hpp 2017-08-16 01:19:09.966298840 -0400 @@ -25,8 +25,6 @@ #ifndef OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP #define OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP -#include "runtime/os.hpp" - inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } @@ -49,8 +47,7 @@ inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); } inline void Atomic::dec_ptr(volatile void* dest) { (void)add_ptr(-1, dest); } -// For Sun Studio - implementation is in solaris_x86_[32/64].il. -// For gcc - implementation is just below. +// For Sun Studio - implementation is in solaris_x86_64.il. extern "C" { jint _Atomic_add(jint add_value, volatile jint* dest); @@ -71,21 +68,51 @@ return _Atomic_xchg(exchange_value, dest); } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg_byte(exchange_value, dest, compare_value); -} - -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg(exchange_value, dest, compare_value); -} - -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg_long(exchange_value, dest, compare_value); +// Not using cmpxchg_using_helper here, because some configurations of +// Solaris compiler don't deal well with passing a "defined in .il" +// function as an argument. We *should* switch to using gcc-style +// inline assembly, but attempting to do so with Studio 12.4 ran into +// segfaults. + +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(1 == sizeof(T)); + return IntegerTypes::cast( + _Atomic_cmpxchg_byte(IntegerTypes::cast(exchange_value), + reinterpret_cast(dest), + IntegerTypes::cast(compare_value))); +} + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); + return IntegerTypes::cast( + _Atomic_cmpxchg(IntegerTypes::cast(exchange_value), + reinterpret_cast(dest), + IntegerTypes::cast(compare_value))); +} + +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); + return IntegerTypes::cast( + _Atomic_cmpxchg_long(IntegerTypes::cast(exchange_value), + reinterpret_cast(dest), + IntegerTypes::cast(compare_value))); } - -#ifdef AMD64 inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } extern "C" jlong _Atomic_add_long(jlong add_value, volatile jlong* dest); @@ -107,59 +134,6 @@ return (void*)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest); } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)_Atomic_cmpxchg_long((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)_Atomic_cmpxchg_long((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value); -} - inline jlong Atomic::load(const volatile jlong* src) { return *src; } -#else // !AMD64 - -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - return (intptr_t)add((jint)add_value, (volatile jint*)dest); -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add((jint)add_value, (volatile jint*)dest); -} - -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest); -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg((jint)exchange_value, (volatile jint*)dest); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -extern "C" void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst); - -inline jlong Atomic::load(const volatile jlong* src) { - volatile jlong dest; - _Atomic_move_long(src, &dest); - return dest; -} - -inline void Atomic::store(jlong store_value, jlong* dest) { - _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest); -} - -inline void Atomic::store(jlong store_value, volatile jlong* dest) { - _Atomic_move_long((volatile jlong*)&store_value, dest); -} - -#endif // AMD64 - - #endif // OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP --- old/src/os_cpu/windows_x86/vm/atomic_windows_x86.hpp 2017-08-16 01:19:10.610331873 -0400 +++ new/src/os_cpu/windows_x86/vm/atomic_windows_x86.hpp 2017-08-16 01:19:10.498326129 -0400 @@ -109,26 +109,22 @@ return (void *)(os::atomic_xchg_ptr_func)((intptr_t)exchange_value, (volatile intptr_t*)dest); } -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { - return (*os::atomic_cmpxchg_func)(exchange_value, dest, compare_value); -} - -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { - return (*os::atomic_cmpxchg_byte_func)(exchange_value, dest, compare_value); -} - -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - return (*os::atomic_cmpxchg_long_func)(exchange_value, dest, compare_value); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} +#define DEFINE_STUB_CMPXCHG(ByteSize, StubType, StubName) \ + template<> \ + template \ + inline T Atomic::PlatformCmpxchg::operator()(T exchange_value, \ + T volatile* dest, \ + T compare_value, \ + cmpxchg_memory_order order) const { \ + STATIC_ASSERT(ByteSize == sizeof(T)); \ + return cmpxchg_using_helper(StubName, exchange_value, dest, compare_value); \ + } + +DEFINE_STUB_CMPXCHG(1, jbyte, os::atomic_cmpxchg_byte_func) +DEFINE_STUB_CMPXCHG(4, jint, os::atomic_cmpxchg_func) +DEFINE_STUB_CMPXCHG(8, jlong, os::atomic_cmpxchg_long_func) -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} +#undef DEFINE_STUB_CMPXCHG inline jlong Atomic::load(const volatile jlong* src) { return *src; } @@ -201,8 +197,13 @@ return (void*)xchg((jint)exchange_value, (volatile jint*)dest); } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(1 == sizeof(T)); // alternative for InterlockedCompareExchange __asm { mov edx, dest @@ -212,7 +213,13 @@ } } -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); // alternative for InterlockedCompareExchange __asm { mov edx, dest @@ -222,7 +229,13 @@ } } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); jint ex_lo = (jint)exchange_value; jint ex_hi = *( ((jint*)&exchange_value) + 1 ); jint cmp_lo = (jint)compare_value; @@ -241,14 +254,6 @@ } } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - inline jlong Atomic::load(const volatile jlong* src) { volatile jlong dest; volatile jlong* pdest = &dest; --- old/src/share/vm/aot/aotCodeHeap.cpp 2017-08-16 01:19:11.146359371 -0400 +++ new/src/share/vm/aot/aotCodeHeap.cpp 2017-08-16 01:19:11.034353621 -0400 @@ -316,7 +316,7 @@ AOTCompiledMethod *aot = new AOTCompiledMethod(code, mh(), meta, metadata_table, metadata_size, state_adr, this, name, code_id, _aot_id); assert(_code_to_aot[code_id]._aot == NULL, "should be not initialized"); _code_to_aot[code_id]._aot = aot; // Should set this first - if (Atomic::cmpxchg(in_use, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) { + if (Atomic::cmpxchg(in_use, &_code_to_aot[code_id]._state, not_set) != not_set) { _code_to_aot[code_id]._aot = NULL; // Clean } else { // success // Publish method @@ -378,7 +378,7 @@ AOTCompiledMethod* aot = new AOTCompiledMethod(entry, NULL, meta, metadata_table, metadata_size, state_adr, this, full_name, code_id, i); assert(_code_to_aot[code_id]._aot == NULL, "should be not initialized"); _code_to_aot[code_id]._aot = aot; - if (Atomic::cmpxchg(in_use, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) { + if (Atomic::cmpxchg(in_use, &_code_to_aot[code_id]._state, not_set) != not_set) { fatal("stab '%s' code state is %d", full_name, _code_to_aot[code_id]._state); } // Adjust code buffer boundaries only for stubs because they are last in the buffer. @@ -649,7 +649,7 @@ for (int i = 0; i < methods_cnt; ++i) { int code_id = indexes[i]; // Invalidate aot code. - if (Atomic::cmpxchg(invalid, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) { + if (Atomic::cmpxchg(invalid, &_code_to_aot[code_id]._state, not_set) != not_set) { if (_code_to_aot[code_id]._state == in_use) { AOTCompiledMethod* aot = _code_to_aot[code_id]._aot; assert(aot != NULL, "aot should be set"); --- old/src/share/vm/aot/aotCodeHeap.hpp 2017-08-16 01:19:11.686387064 -0400 +++ new/src/share/vm/aot/aotCodeHeap.hpp 2017-08-16 01:19:11.574381319 -0400 @@ -26,6 +26,8 @@ #include "aot/aotCompiledMethod.hpp" #include "classfile/symbolTable.hpp" +#include "metaprogramming/integralConstant.hpp" +#include "metaprogramming/isRegisteredEnum.hpp" #include "oops/metadata.hpp" #include "oops/method.hpp" @@ -35,6 +37,8 @@ invalid = 2 // AOT code is invalidated because dependencies failed }; +template<> struct IsRegisteredEnum : public TrueType {}; + typedef struct { AOTCompiledMethod* _aot; CodeState _state; // State change cases: not_set->in_use, not_set->invalid --- old/src/share/vm/gc/parallel/psParallelCompact.hpp 2017-08-16 01:19:12.214414141 -0400 +++ new/src/share/vm/gc/parallel/psParallelCompact.hpp 2017-08-16 01:19:12.102408397 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -593,9 +593,8 @@ inline bool ParallelCompactData::RegionData::claim() { - const int los = (int) live_obj_size(); - const int old = Atomic::cmpxchg(dc_claimed | los, - (volatile int*) &_dc_and_los, los); + const region_sz_t los = static_cast(live_obj_size()); + const region_sz_t old = Atomic::cmpxchg(dc_claimed | los, &_dc_and_los, los); return old == los; } --- old/src/share/vm/gc/shared/workgroup.cpp 2017-08-16 01:19:12.766442456 -0400 +++ new/src/share/vm/gc/shared/workgroup.cpp 2017-08-16 01:19:12.654436717 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -428,7 +428,7 @@ assert(t < _n_tasks, "bad task id."); uint old = _tasks[t]; if (old == 0) { - old = Atomic::cmpxchg(1, &_tasks[t], 0); + old = Atomic::cmpxchg(1u, &_tasks[t], 0u); } assert(_tasks[t] == 1, "What else?"); bool res = old != 0; @@ -442,15 +442,15 @@ } void SubTasksDone::all_tasks_completed(uint n_threads) { - jint observed = _threads_completed; - jint old; + uint observed = _threads_completed; + uint old; do { old = observed; observed = Atomic::cmpxchg(old+1, &_threads_completed, old); } while (observed != old); // If this was the last thread checking in, clear the tasks. uint adjusted_thread_count = (n_threads == 0 ? 1 : n_threads); - if (observed + 1 == (jint)adjusted_thread_count) { + if (observed + 1 == adjusted_thread_count) { clear(); } } @@ -474,8 +474,8 @@ bool SequentialSubTasksDone::is_task_claimed(uint& t) { t = _n_claimed; while (t < _n_tasks) { - jint res = Atomic::cmpxchg(t+1, &_n_claimed, t); - if (res == (jint)t) { + uint res = Atomic::cmpxchg(t+1, &_n_claimed, t); + if (res == t) { return false; } t = res; --- old/src/share/vm/oops/oop.inline.hpp 2017-08-16 01:19:13.306470159 -0400 +++ new/src/share/vm/oops/oop.inline.hpp 2017-08-16 01:19:13.194464414 -0400 @@ -94,7 +94,7 @@ } markOop oopDesc::cas_set_mark(markOop new_mark, markOop old_mark) { - return (markOop) Atomic::cmpxchg_ptr(new_mark, &_mark, old_mark); + return Atomic::cmpxchg(new_mark, &_mark, old_mark); } void oopDesc::init_mark() { @@ -408,14 +408,14 @@ narrowOop val = encode_heap_oop(exchange_value); narrowOop cmp = encode_heap_oop(compare_value); - narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp); + narrowOop old = Atomic::cmpxchg(val, (narrowOop*)dest, cmp); // decode old from T to oop return decode_heap_oop(old); } else { if (prebarrier) { update_barrier_set_pre((oop*)dest, exchange_value); } - return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value); + return Atomic::cmpxchg(exchange_value, (oop*)dest, compare_value); } } @@ -616,7 +616,7 @@ assert(sizeof(markOop) == sizeof(intptr_t), "CAS below requires this."); while (!oldMark->is_marked()) { - curMark = (markOop)Atomic::cmpxchg_ptr(forwardPtrMark, &_mark, oldMark); + curMark = Atomic::cmpxchg(forwardPtrMark, &_mark, oldMark); assert(is_forwarded(), "object should have been forwarded"); if (curMark == oldMark) { return NULL; --- old/src/share/vm/oops/oopsHierarchy.hpp 2017-08-16 01:19:13.842497651 -0400 +++ new/src/share/vm/oops/oopsHierarchy.hpp 2017-08-16 01:19:13.730491906 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ #ifndef SHARE_VM_OOPS_OOPSHIERARCHY_HPP #define SHARE_VM_OOPS_OOPSHIERARCHY_HPP +#include "metaprogramming/integerTypes.hpp" +#include "metaprogramming/integralConstant.hpp" #include "runtime/globals.hpp" #include "utilities/globalDefinitions.hpp" @@ -142,6 +144,15 @@ operator oop* () const { return (oop *)obj(); } }; +template<> +struct IntegerTypes::Translate : public TrueType { + typedef oop Value; + typedef oopDesc* Decayed; + + static Decayed decay(Value x) { return x.obj(); } + static Value recover(Decayed x) { return oop(x); } +}; + #define DEF_OOP(type) \ class type##OopDesc; \ class type##Oop : public oop { \ --- old/src/share/vm/runtime/atomic.hpp 2017-08-16 01:19:14.378525136 -0400 +++ new/src/share/vm/runtime/atomic.hpp 2017-08-16 01:19:14.266519391 -0400 @@ -26,6 +26,11 @@ #define SHARE_VM_RUNTIME_ATOMIC_HPP #include "memory/allocation.hpp" +#include "metaprogramming/enableIf.hpp" +#include "metaprogramming/integerTypes.hpp" +#include "metaprogramming/isIntegral.hpp" +#include "metaprogramming/isSame.hpp" +#include "metaprogramming/removeCV.hpp" #include "utilities/align.hpp" #include "utilities/macros.hpp" @@ -111,13 +116,132 @@ // *dest with exchange_value if the comparison succeeded. Returns prior // value of *dest. cmpxchg*() provide: // compare-and-exchange - inline static jbyte cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order = memory_order_conservative); - inline static jint cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order = memory_order_conservative); - // See comment above about using jlong atomics on 32-bit platforms - inline static jlong cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order = memory_order_conservative); - inline static unsigned int cmpxchg (unsigned int exchange_value, volatile unsigned int* dest, unsigned int compare_value, cmpxchg_memory_order order = memory_order_conservative); - inline static intptr_t cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order = memory_order_conservative); - inline static void* cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order = memory_order_conservative); + + template + inline static D cmpxchg(T exchange_value, + D volatile* dest, + U compare_value, + cmpxchg_memory_order order = memory_order_conservative); + + // Performs atomic compare of *dest and NULL, and replaces *dest + // with exchange_value if the comparison succeeded. Returns true if + // the comparison succeeded and the exchange occurred. This is + // often used as part of lazy initialization, as a lock-free + // alternative to the Double-Checked Locking Pattern. + template + inline static bool replace_if_null(T* value, D* volatile* dest, + cmpxchg_memory_order order = memory_order_conservative); + + inline static intptr_t cmpxchg_ptr(intptr_t exchange_value, + volatile intptr_t* dest, + intptr_t compare_value, + cmpxchg_memory_order order = memory_order_conservative) { + return cmpxchg(exchange_value, dest, compare_value, order); + } + + inline static void* cmpxchg_ptr(void* exchange_value, + volatile void* dest, + void* compare_value, + cmpxchg_memory_order order = memory_order_conservative) { + return cmpxchg(exchange_value, + reinterpret_cast(dest), + compare_value, + order); + } + +private: + // Test whether From is implicitly convertible to To. + // From and To must be pointer types. + // Note: Provides the limited subset of C++11 std::is_convertible + // that is needed here. + template struct IsPointerConvertible; + + // Dispatch handler for cmpxchg. Provides type-based validity + // checking and limited conversions around calls to the + // platform-specific implementation layer provided by + // PlatformCmpxchg. + template + struct CmpxchgImpl; + + // Platform-specific implementation of cmpxchg. Support for sizes + // of 1, 4, and 8 are required. The class is a function object that + // must be default constructable, with these requirements: + // + // - dest is of type T*. + // - exchange_value and compare_value are of type T. + // - order is of type cmpxchg_memory_order. + // - platform_cmpxchg is an object of type PlatformCmpxchg. + // + // Then + // platform_cmpxchg(exchange_value, dest, compare_value, order) + // must be a valid expression, returning a result convertible to T. + // + // A default definition is provided, which declares a function template + // T operator()(T, T volatile*, T, cmpxchg_memory_order) const + // + // For each required size, a platform must either provide an + // appropriate definition of that function, or must entirely + // specialize the class template for that size. + template struct PlatformCmpxchg; + + // Support for platforms that implement some variants of cmpxchg + // using a (typically out of line) non-template helper function. + // The generic arguments passed to PlatformCmpxchg need to be + // translated to the appropriate type for the helper function, the + // helper invoked on the translated arguments, and the result + // translated back. Type is the parameter / return type of the + // helper function. + template + static T cmpxchg_using_helper(Fn fn, + T exchange_value, + T volatile* dest, + T compare_value); + + // Support platforms that do not provide Read-Modify-Write + // byte-level atomic access. To use, derive PlatformCmpxchg<1> from + // this class. +public: // Temporary, can't be private: C++03 11.4/2. Fixed by C++11. + struct CmpxchgByteUsingInt; +private: +}; + +template +struct Atomic::IsPointerConvertible : AllStatic { + // Determine whether From* is implicitly convertible to To*, using + // the "sizeof trick". + typedef char yes; + typedef char (&no)[2]; + + static yes test(To*); + static no test(...); + static From* test_value; + + static const bool value = (sizeof(yes) == sizeof(test(test_value))); +}; + +// Define the class before including platform file, which may specialize +// the operator definition. No generic definition of specializations +// of the operator template are provided, nor are there any generic +// specializations of the class. The platform file is responsible for +// providing those. +template +struct Atomic::PlatformCmpxchg VALUE_OBJ_CLASS_SPEC { + template + T operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const; +}; + +// Define the class before including platform file, which may use this +// as a base class, requiring it be complete. The definition is later +// in this file, near the other definitions related to cmpxchg. +struct Atomic::CmpxchgByteUsingInt VALUE_OBJ_CLASS_SPEC { + template + T operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const; }; // platform specific in-line definitions - must come before shared definitions @@ -143,61 +267,152 @@ dec_ptr((volatile intptr_t*) dest); } -#ifndef VM_HAS_SPECIALIZED_CMPXCHG_BYTE -/* - * This is the default implementation of byte-sized cmpxchg. It emulates jbyte-sized cmpxchg - * in terms of jint-sized cmpxchg. Platforms may override this by defining their own inline definition - * as well as defining VM_HAS_SPECIALIZED_CMPXCHG_BYTE. This will cause the platform specific - * implementation to be used instead. - */ -inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, - jbyte compare_value, cmpxchg_memory_order order) { - STATIC_ASSERT(sizeof(jbyte) == 1); - volatile jint* dest_int = - reinterpret_cast(align_down(dest, sizeof(jint))); - size_t offset = pointer_delta(dest, dest_int, 1); - jint cur = *dest_int; - jbyte* cur_as_bytes = reinterpret_cast(&cur); +template +inline D Atomic::cmpxchg(T exchange_value, + D volatile* dest, + U compare_value, + cmpxchg_memory_order order) { + return CmpxchgImpl()(exchange_value, dest, compare_value, order); +} + +template +inline bool Atomic::replace_if_null(T* value, D* volatile* dest, + cmpxchg_memory_order order) { + // Presently using a trivial implementation in terms of cmpxchg. + // Consider adding platform support, to permit the use of compiler + // intrinsics like gcc's __sync_bool_compare_and_swap. + D* expected_null = NULL; + return expected_null == cmpxchg(value, dest, expected_null, order); +} + +// Handle cmpxchg for integral and enum types. +// +// All the involved types must be identical. +template +struct Atomic::CmpxchgImpl< + T, T, T, + typename EnableIf::value || IsRegisteredEnum::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(T exchange_value, T volatile* dest, T compare_value, + cmpxchg_memory_order order) const { + // Forward to the platform handler for the size of T. + return PlatformCmpxchg()(exchange_value, + dest, + compare_value, + order); + } +}; + +// Handle cmpxchg for pointer types. +// +// The destination's type and the compare_value type must be the same, +// ignoring cv-qualifiers; we don't care about the cv-qualifiers of +// the compare_value. +// +// The exchange_value must be implicitly convertible to the +// destination's type; it must be type-correct to store the +// exchange_value in the destination. +template +struct Atomic::CmpxchgImpl< + T*, D*, U*, + typename EnableIf::value && + IsSame::type, + typename RemoveCV::type>::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + D* operator()(T* exchange_value, D* volatile* dest, U* compare_value, + cmpxchg_memory_order order) const { + // Allow derived to base conversion, and adding cv-qualifiers. + D* new_value = exchange_value; + // Don't care what the CV qualifiers for compare_value are, + // but we need to match D* when calling platform support. + D* old_value = const_cast(compare_value); + return PlatformCmpxchg()(new_value, dest, old_value, order); + } +}; + +// Handle cmpxchg for types that have a translator. +// +// All the involved types must be identical. +// +// This translates the original call into a call on the decayed +// arguments, and returns the recovered result of that translated +// call. +template +struct Atomic::CmpxchgImpl< + T, T, T, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(T exchange_value, T volatile* dest, T compare_value, + cmpxchg_memory_order order) const { + typedef IntegerTypes::Translate Translator; + typedef typename Translator::Decayed Decayed; + STATIC_ASSERT(sizeof(T) == sizeof(Decayed)); + return Translator::recover( + cmpxchg(Translator::decay(exchange_value), + reinterpret_cast(dest), + Translator::decay(compare_value), + order)); + } +}; + +template +inline T Atomic::cmpxchg_using_helper(Fn fn, + T exchange_value, + T volatile* dest, + T compare_value) { + STATIC_ASSERT(sizeof(Type) == sizeof(T)); + return IntegerTypes::cast( + fn(IntegerTypes::cast(exchange_value), + reinterpret_cast(dest), + IntegerTypes::cast(compare_value))); +} + +template +inline T Atomic::CmpxchgByteUsingInt::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(sizeof(T) == sizeof(uint8_t)); + uint8_t canon_exchange_value = exchange_value; + uint8_t canon_compare_value = compare_value; + volatile uint32_t* aligned_dest + = reinterpret_cast(align_down(dest, sizeof(uint32_t))); + size_t offset = pointer_delta(dest, aligned_dest, 1); + uint32_t cur = *aligned_dest; + uint8_t* cur_as_bytes = reinterpret_cast(&cur); // current value may not be what we are looking for, so force it // to that value so the initial cmpxchg will fail if it is different - cur_as_bytes[offset] = compare_value; + cur_as_bytes[offset] = canon_compare_value; // always execute a real cmpxchg so that we get the required memory // barriers even on initial failure do { // value to swap in matches current value ... - jint new_value = cur; + uint32_t new_value = cur; // ... except for the one jbyte we want to update - reinterpret_cast(&new_value)[offset] = exchange_value; + reinterpret_cast(&new_value)[offset] = canon_exchange_value; - jint res = cmpxchg(new_value, dest_int, cur, order); - if (res == cur) break; // success + uint32_t res = cmpxchg(new_value, aligned_dest, cur, order); + if (res == cur) break; // success - // at least one jbyte in the jint changed value, so update - // our view of the current jint + // at least one byte in the int changed value, so update + // our view of the current int cur = res; - // if our jbyte is still as cur we loop and try again - } while (cur_as_bytes[offset] == compare_value); + // if our byte is still as cur we loop and try again + } while (cur_as_bytes[offset] == canon_compare_value); - return cur_as_bytes[offset]; + return IntegerTypes::cast(cur_as_bytes[offset]); } -#endif // VM_HAS_SPECIALIZED_CMPXCHG_BYTE - inline unsigned Atomic::xchg(unsigned int exchange_value, volatile unsigned int* dest) { assert(sizeof(unsigned int) == sizeof(jint), "more work to do"); return (unsigned int)Atomic::xchg((jint)exchange_value, (volatile jint*)dest); } -inline unsigned Atomic::cmpxchg(unsigned int exchange_value, - volatile unsigned int* dest, unsigned int compare_value, - cmpxchg_memory_order order) { - assert(sizeof(unsigned int) == sizeof(jint), "more work to do"); - return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest, - (jint)compare_value, order); -} - inline jshort Atomic::add(jshort add_value, volatile jshort* dest) { // Most platforms do not support atomic add on a 2-byte value. However, // if the value occupies the most significant 16 bits of an aligned 32-bit --- old/src/share/vm/runtime/os.cpp 2017-08-16 01:19:14.918552834 -0400 +++ new/src/share/vm/runtime/os.cpp 2017-08-16 01:19:14.806547087 -0400 @@ -755,9 +755,9 @@ // Make updating the random seed thread safe. while (true) { unsigned int seed = _rand_seed; - int rand = random_helper(seed); + unsigned int rand = random_helper(seed); if (Atomic::cmpxchg(rand, &_rand_seed, seed) == seed) { - return rand; + return static_cast(rand); } } } --- old/src/share/vm/utilities/bitMap.cpp 2017-08-16 01:19:15.470581146 -0400 +++ new/src/share/vm/utilities/bitMap.cpp 2017-08-16 01:19:15.358575402 -0400 @@ -210,12 +210,12 @@ // With a valid range (beg <= end), this test ensures that end != 0, as // required by inverted_bit_mask_for_range. Also avoids an unnecessary write. if (beg != end) { - intptr_t* pw = (intptr_t*)word_addr(beg); - intptr_t w = *pw; - intptr_t mr = (intptr_t)inverted_bit_mask_for_range(beg, end); - intptr_t nw = value ? (w | ~mr) : (w & mr); + bm_word_t* pw = word_addr(beg); + bm_word_t w = *pw; + bm_word_t mr = inverted_bit_mask_for_range(beg, end); + bm_word_t nw = value ? (w | ~mr) : (w & mr); while (true) { - intptr_t res = Atomic::cmpxchg_ptr(nw, pw, w); + bm_word_t res = Atomic::cmpxchg(nw, pw, w); if (res == w) break; w = res; nw = value ? (w | ~mr) : (w & mr); @@ -617,7 +617,7 @@ return true; } -BitMap::idx_t* BitMap::_pop_count_table = NULL; +const BitMap::idx_t* BitMap::_pop_count_table = NULL; void BitMap::init_pop_count_table() { if (_pop_count_table == NULL) { @@ -626,11 +626,8 @@ table[i] = num_set_bits(i); } - intptr_t res = Atomic::cmpxchg_ptr((intptr_t) table, - (intptr_t*) &_pop_count_table, - (intptr_t) NULL_WORD); - if (res != NULL_WORD) { - guarantee( _pop_count_table == (void*) res, "invariant" ); + if (!Atomic::replace_if_null(table, &_pop_count_table)) { + guarantee(_pop_count_table != NULL, "invariant"); FREE_C_HEAP_ARRAY(idx_t, table); } } --- old/src/share/vm/utilities/bitMap.hpp 2017-08-16 01:19:16.002608431 -0400 +++ new/src/share/vm/utilities/bitMap.hpp 2017-08-16 01:19:15.890602688 -0400 @@ -114,7 +114,7 @@ void verify_range(idx_t beg_index, idx_t end_index) const NOT_DEBUG_RETURN; // Statistics. - static idx_t* _pop_count_table; + static const idx_t* _pop_count_table; static void init_pop_count_table(); static idx_t num_set_bits(bm_word_t w); static idx_t num_set_bits_from_table(unsigned char c); --- old/src/share/vm/utilities/bitMap.inline.hpp 2017-08-16 01:19:16.538635924 -0400 +++ new/src/share/vm/utilities/bitMap.inline.hpp 2017-08-16 01:19:16.426630185 -0400 @@ -49,9 +49,7 @@ if (new_val == old_val) { return false; // Someone else beat us to it. } - const bm_word_t cur_val = (bm_word_t) Atomic::cmpxchg_ptr((void*) new_val, - (volatile void*) addr, - (void*) old_val); + const bm_word_t cur_val = Atomic::cmpxchg(new_val, addr, old_val); if (cur_val == old_val) { return true; // Success. } @@ -70,9 +68,7 @@ if (new_val == old_val) { return false; // Someone else beat us to it. } - const bm_word_t cur_val = (bm_word_t) Atomic::cmpxchg_ptr((void*) new_val, - (volatile void*) addr, - (void*) old_val); + const bm_word_t cur_val = Atomic::cmpxchg(new_val, addr, old_val); if (cur_val == old_val) { return true; // Success. } --- /dev/null 2017-08-13 17:24:39.427578209 -0400 +++ new/src/share/vm/metaprogramming/integerTypes.hpp 2017-08-16 01:19:16.966657882 -0400 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP +#define SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP + +#include "memory/allocation.hpp" +#include "metaprogramming/enableIf.hpp" +#include "metaprogramming/integralConstant.hpp" +#include "metaprogramming/isFloatingPoint.hpp" +#include "metaprogramming/isIntegral.hpp" +#include "metaprogramming/isRegisteredEnum.hpp" +#include "utilities/debug.hpp" + +class IntegerTypes : public AllStatic { +public: + // Return a value of type T with the same representation as x. + // + // T and U must be of the same size. + // + // At least one of T or U must be an integral type. The other must + // be an integral, floating point, or pointer type. + template static T cast(U x); + + // Support thin wrappers over primitive types. + // If derived from TrueType, provides representational conversion + // from T to some other type. When true, must provide + // - Value: typedef for T. + // - Decayed: typedef for decayed type. + // - static Decayed decay(T x): return value of type Decayed with + // the same representation as x. + // - static T recover(Decayed x): return a value of type T with the + // same representation as x. + template struct Translate : public FalseType {}; + +private: + + template + struct Cast; + + template static T cast_using_union(U x); +}; + +// Return an object of type T with the same value representation as x. +// +// T and U must be of the same size. It is expected that one of T and +// U is an integral type, and the other is an integral type, a +// (registered) enum type, or a floating point type +// +// This implementation uses the "union trick", which seems to be the +// best of a bad set of options. Though technically undefined +// behavior, it is widely and well supported, producing good code. In +// some cases, such as gcc, that support is explicitly documented. +// +// Using memcpy is the correct method, but some compilers produce +// wretched code for that method, even at maximal optimization levels. +// +// Using static_cast is only possible for integral and enum types, not +// for floating point types. And for integral and enum conversions, +// static_cast has unspecified or implementation-defined behavior for +// some cases. C++11 can be used to avoid most or all +// of those unspecified or implementation-defined issues, though that +// may require multi-step conversions. +// +// Using reinterpret_cast of references has undefined behavior for +// many cases, and there is much less empirical basis for its use, as +// compared to the union trick. +template +inline T IntegerTypes::cast_using_union(U x) { + STATIC_ASSERT(sizeof(T) == sizeof(U)); + union { T t; U u; }; + u = x; + return t; +} + +////////////////////////////////////////////////////////////////////////////// +// cast(x) +// +// Cast + +// Give an informative error if the sizes differ. +template +struct IntegerTypes::Cast VALUE_OBJ_CLASS_SPEC { + STATIC_ASSERT(sizeof(T) == sizeof(U)); +}; + +// Conversion between integral types. +template +struct IntegerTypes::Cast< + T, U, true, + typename EnableIf::value && IsIntegral::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(U x) const { return cast_using_union(x); } +}; + +// Convert an enum or floating point value to an integer value. +template +struct IntegerTypes::Cast< + T, U, true, + typename EnableIf::value && + (IsRegisteredEnum::value || + IsFloatingPoint::value)>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(U x) const { return cast_using_union(x); } +}; + +// Convert an integer to an enum or floating point value. +template +struct IntegerTypes::Cast< + T, U, true, + typename EnableIf::value && + (IsRegisteredEnum::value || + IsFloatingPoint::value)>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(U x) const { return cast_using_union(x); } +}; + +// Convert a pointer to an integral value. +template +struct IntegerTypes::Cast< + T, U*, true, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(U* x) const { return reinterpret_cast(x); } +}; + +// Convert an integral value to a pointer. +template +struct IntegerTypes::Cast< + T*, U, true, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T* operator()(U x) const { return reinterpret_cast(x); } +}; + +template +inline T IntegerTypes::cast(U x) { + return Cast()(x); +} + +#endif // SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP --- /dev/null 2017-08-13 17:24:39.427578209 -0400 +++ new/src/share/vm/metaprogramming/isRegisteredEnum.hpp 2017-08-16 01:19:17.454682905 -0400 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP +#define SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP + +#include "memory/allocation.hpp" +#include "metaprogramming/integralConstant.hpp" + +// Recognize registered enum types. +// Registration is by specializing this trait. +// +// This is a manual stand-in for the C++11 std::is_enum type trait. +// It's a lot of work to implement is_enum portably in C++98, so this +// manual approach is being taken for those enum types we need to +// distinguish. +template +struct IsRegisteredEnum : public FalseType {}; + +#endif // SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP + --- /dev/null 2017-08-13 17:24:39.427578209 -0400 +++ new/test/native/metaprogramming/test_integerTypes.cpp 2017-08-16 01:19:17.974709583 -0400 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/allocation.hpp" +#include "metaprogramming/integerTypes.hpp" +#include "metaprogramming/isSame.hpp" +#include "unittest.hpp" +#include "utilities/debug.hpp" + +struct IntegerTypesTestSupport: AllStatic { + + template struct SignedTypeOfSize; + template struct UnsignedTypeOfSize; + + template struct Signed; + template struct Unsigned; +}; + +#define DEFINE_CANONICAL_SIGNED_TYPE(T) \ + template<> \ + struct IntegerTypesTestSupport::SignedTypeOfSize \ + : public AllStatic \ + { \ + typedef T type; \ + }; + +#define DEFINE_CANONICAL_UNSIGNED_TYPE(T) \ + template<> \ + struct IntegerTypesTestSupport::UnsignedTypeOfSize \ + : public AllStatic \ + { \ + typedef T type; \ + }; + +#define DEFINE_INTEGER_TYPES_OF_SIZE(NBITS) \ + DEFINE_CANONICAL_SIGNED_TYPE(int ## NBITS ## _t) \ + DEFINE_CANONICAL_UNSIGNED_TYPE(uint ## NBITS ## _t) + +DEFINE_INTEGER_TYPES_OF_SIZE(8) +DEFINE_INTEGER_TYPES_OF_SIZE(16) +DEFINE_INTEGER_TYPES_OF_SIZE(32) +DEFINE_INTEGER_TYPES_OF_SIZE(64) + +#undef DEFINE_INTEGER_TYPES_OF_SIZE +#undef DEFINE_CANONICAL_SIGNED_TYPE +#undef DEFINE_CANONICAL_UNSIGNED_TYPE + +template +struct IntegerTypesTestSupport::Signed + : public SignedTypeOfSize +{}; + +template +struct IntegerTypesTestSupport::Unsigned + : public UnsignedTypeOfSize +{}; + +TEST(IntegerTypesTest, round_trip_int) { + int sfive = 5; + int mfive = -5; + uint ufive = 5u; + + typedef IntegerTypesTestSupport::Signed::type SI; + typedef IntegerTypesTestSupport::Unsigned::type UI; + + EXPECT_EQ(sfive, IntegerTypes::cast(IntegerTypes::cast(sfive))); + EXPECT_EQ(sfive, IntegerTypes::cast(IntegerTypes::cast(sfive))); + + EXPECT_EQ(mfive, IntegerTypes::cast(IntegerTypes::cast(mfive))); + EXPECT_EQ(mfive, IntegerTypes::cast(IntegerTypes::cast(mfive))); + + EXPECT_EQ(ufive, IntegerTypes::cast(IntegerTypes::cast(ufive))); + EXPECT_EQ(ufive, IntegerTypes::cast(IntegerTypes::cast(ufive))); +} + +TEST(IntegerTypesTest, round_trip_float) { + float ffive = 5.0f; + double dfive = 5.0; + + typedef IntegerTypesTestSupport::Signed::type SF; + typedef IntegerTypesTestSupport::Unsigned::type UF; + + typedef IntegerTypesTestSupport::Signed::type SD; + typedef IntegerTypesTestSupport::Unsigned::type UD; + + EXPECT_EQ(ffive, IntegerTypes::cast(IntegerTypes::cast(ffive))); + EXPECT_EQ(ffive, IntegerTypes::cast(IntegerTypes::cast(ffive))); + + EXPECT_EQ(dfive, IntegerTypes::cast(IntegerTypes::cast(dfive))); + EXPECT_EQ(dfive, IntegerTypes::cast(IntegerTypes::cast(dfive))); +} + +TEST(IntegerTypesTest, round_trip_ptr) { + int five = 5; + int* pfive = &five; + const int* cpfive = &five; + + typedef IntegerTypesTestSupport::Signed::type SIP; + typedef IntegerTypesTestSupport::Unsigned::type UIP; + + EXPECT_EQ(pfive, IntegerTypes::cast(IntegerTypes::cast(pfive))); + EXPECT_EQ(pfive, IntegerTypes::cast(IntegerTypes::cast(pfive))); + + EXPECT_EQ(cpfive, IntegerTypes::cast(IntegerTypes::cast(cpfive))); + EXPECT_EQ(cpfive, IntegerTypes::cast(IntegerTypes::cast(cpfive))); +} --- /dev/null 2017-08-13 17:24:39.427578209 -0400 +++ new/test/native/metaprogramming/test_isRegisteredEnum.cpp 2017-08-16 01:19:18.462734606 -0400 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/allocation.hpp" +#include "metaprogramming/integralConstant.hpp" +#include "metaprogramming/isRegisteredEnum.hpp" + +#include "unittest.hpp" + +struct IsRegisteredEnumTest : AllStatic { + enum A { A_x, A_y, A_z }; + enum B { B_x, B_y, B_z }; +}; + +typedef IsRegisteredEnumTest::A A; +typedef IsRegisteredEnumTest::B B; + +template<> struct IsRegisteredEnum : public TrueType {}; + +STATIC_ASSERT(!IsRegisteredEnum::value); +STATIC_ASSERT(IsRegisteredEnum::value); +STATIC_ASSERT(!IsRegisteredEnum::value);