8186166: Generalize Atomic::cmpxchg with templates

Reviewed-by: dholmes, coleenp
This commit is contained in:
Kim Barrett 2017-08-23 14:01:17 +02:00 committed by Erik Österlund
parent 61a9f88ca7
commit e54adefc2f
31 changed files with 1046 additions and 518 deletions

View File

@ -952,7 +952,7 @@ jlong os::javaTimeNanos() {
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

View File

@ -1197,7 +1197,7 @@ inline hrtime_t getTimeNanos() {
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

View File

@ -306,8 +306,13 @@ inline void cmpxchg_post_membar(cmpxchg_memory_order order) {
}
}
#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<typename T>
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 @@ inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte c
cmpxchg_post_membar(order);
return (jbyte)(unsigned char)old_value;
return PrimitiveConversions::cast<T>((unsigned char)old_value);
}
inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
template<>
template<typename T>
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 @@ inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compa
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<typename T>
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 @@ inline jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong* dest, jlong c
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

View File

@ -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 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* des
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<typename T>
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 @@ inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte*
return exchange_value;
}
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
template<>
template<typename T>
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 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* des
return exchange_value;
}
inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) {
template<>
template<typename T>
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 @@ inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong*
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 @@ extern "C" {
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<typename T>
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<jlong>(_Atomic_cmpxchg_long, exchange_value, dest, compare_value);
}
inline jlong Atomic::load(const volatile jlong* src) {

View File

@ -57,9 +57,9 @@ static inline int __m68k_cmpxchg(int oldval, int newval, volatile int *ptr) {
/* 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 @@ typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
/* 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,55 +267,38 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
(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<typename T>
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));
#ifdef ARM
return arm_compare_and_swap(dest, compare_value, exchange_value);
return cmpxchg_using_helper<int>(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<int>(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) {
template<>
template<typename T>
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));
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
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) {
volatile jlong dest;
os::atomic_copy64(src, &dest);

View File

@ -85,9 +85,13 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest)
(volatile intptr_t*) dest);
}
template <typename T> T generic_cmpxchg(T exchange_value, volatile T* dest,
T compare_value, cmpxchg_memory_order order)
{
template<size_t byte_size>
template<typename T>
inline T Atomic::PlatformCmpxchg<byte_size>::operator()(T exchange_value,
T volatile* dest,
T compare_value,
cmpxchg_memory_order 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 @@ template <typename T> T generic_cmpxchg(T exchange_value, volatile 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)
{
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 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* des
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

View File

@ -200,9 +200,38 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
// 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<typename T>
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 @@ inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compa
: "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<jint>(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<typename T>
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 @@ inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong
: "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);
return cmpxchg_using_helper<jlong>(reorder_cmpxchg_long_func, exchange_value, dest, compare_value);
#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);
#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

View File

@ -306,8 +306,13 @@ inline void cmpxchg_post_membar(cmpxchg_memory_order order) {
}
}
#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<typename T>
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 @@ inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte c
cmpxchg_post_membar(order);
return (jbyte)(unsigned char)old_value;
return PrimitiveConversions::cast<T>((unsigned char)old_value);
}
inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
template<>
template<typename T>
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 @@ inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compa
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<typename T>
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 @@ inline jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong* dest, jlong c
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

View File

@ -478,8 +478,18 @@ inline void *Atomic::xchg_ptr(void *exchange_value, volatile void *dest) {
// 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) {
unsigned long old;
// No direct support for cmpxchg of bytes; emulate using int.
template<>
struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
template<>
template<typename T>
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));
T old;
__asm__ __volatile__ (
" CS %[old],%[upd],%[mem] \n\t" // Try to xchg upd with mem.
@ -493,11 +503,17 @@ jint Atomic::cmpxchg(jint xchg_val, volatile jint* dest, jint cmp_val, cmpxchg_m
: "cc", "memory"
);
return (jint)old;
return old;
}
jlong Atomic::cmpxchg(jlong xchg_val, volatile jlong* dest, jlong cmp_val, cmpxchg_memory_order unused) {
unsigned long old;
template<>
template<typename T>
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 @@ jlong Atomic::cmpxchg(jlong xchg_val, volatile jlong* dest, jlong cmp_val, cmpxc
: "cc", "memory"
);
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; }

View File

@ -121,9 +121,18 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* des
return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
}
// No direct support for cmpxchg of bytes; emulate using int.
template<>
struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
jint rv;
template<>
template<typename T>
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)
@ -132,8 +141,14 @@ inline jint Atomic::cmpxchg (jint exchange_value, volatile jint*
return rv;
}
inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) {
jlong rv;
template<>
template<typename T>
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)
@ -142,18 +157,4 @@ inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong*
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

View File

@ -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 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* des
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<typename T>
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 @@ inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte*
return exchange_value;
}
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
template<>
template<typename T>
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 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* des
return exchange_value;
}
inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) {
template<>
template<typename T>
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 @@ inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong*
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 @@ extern "C" {
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<typename T>
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<jlong>(_Atomic_cmpxchg_long, exchange_value, dest, compare_value);
}
inline jlong Atomic::load(const volatile jlong* src) {

View File

@ -57,9 +57,9 @@ static inline int __m68k_cmpxchg(int oldval, int newval, volatile int *ptr) {
/* 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 @@ typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
/* 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,55 +261,38 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
(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<typename T>
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 ARM
return arm_compare_and_swap(dest, compare_value, exchange_value);
return cmpxchg_using_helper<int>(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<int>(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) {
template<>
template<typename T>
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 __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
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) {
volatile jlong dest;
os::atomic_copy64(src, &dest);

View File

@ -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 @@ inline jlong Atomic::load(const volatile jlong* src) { return *src; }
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 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* des
return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
}
// No direct support for cmpxchg of bytes; emulate using int.
template<>
struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
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);
template<>
template<typename T>
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;
}
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);
template<>
template<typename T>
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

View File

@ -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)

View File

@ -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 (volatile jint* dest) { (void)add (-1, dest);
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 @@ inline jint Atomic::xchg (jint exchange_value, volatile jint*
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);
// 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<typename T>
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 PrimitiveConversions::cast<T>(
_Atomic_cmpxchg_byte(PrimitiveConversions::cast<jbyte>(exchange_value),
reinterpret_cast<jbyte volatile*>(dest),
PrimitiveConversions::cast<jbyte>(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);
template<>
template<typename T>
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 PrimitiveConversions::cast<T>(
_Atomic_cmpxchg(PrimitiveConversions::cast<jint>(exchange_value),
reinterpret_cast<jint volatile*>(dest),
PrimitiveConversions::cast<jint>(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);
template<>
template<typename T>
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 PrimitiveConversions::cast<T>(
_Atomic_cmpxchg_long(PrimitiveConversions::cast<jlong>(exchange_value),
reinterpret_cast<jlong volatile*>(dest),
PrimitiveConversions::cast<jlong>(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 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* des
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

View File

@ -109,26 +109,22 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* des
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 DEFINE_STUB_CMPXCHG(ByteSize, StubType, StubName) \
template<> \
template<typename T> \
inline T Atomic::PlatformCmpxchg<ByteSize>::operator()(T exchange_value, \
T volatile* dest, \
T compare_value, \
cmpxchg_memory_order order) const { \
STATIC_ASSERT(ByteSize == sizeof(T)); \
return cmpxchg_using_helper<StubType>(StubName, 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);
}
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 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);
}
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 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* des
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<typename T>
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 jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte*
}
}
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
template<>
template<typename T>
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 jint Atomic::cmpxchg (jint exchange_value, volatile jint*
}
}
inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) {
template<>
template<typename T>
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 jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong*
}
}
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;

View File

@ -316,7 +316,7 @@ void AOTCodeHeap::publish_aot(const methodHandle& mh, AOTMethodData* method_data
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 @@ void AOTCodeHeap::register_stubs() {
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 @@ void AOTCodeHeap::sweep_dependent_methods(AOTKlassData* klass_data) {
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");

View File

@ -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 @@ enum CodeState {
invalid = 2 // AOT code is invalidated because dependencies failed
};
template<> struct IsRegisteredEnum<CodeState> : public TrueType {};
typedef struct {
AOTCompiledMethod* _aot;
CodeState _state; // State change cases: not_set->in_use, not_set->invalid

View File

@ -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 void ParallelCompactData::RegionData::set_highest_ref(HeapWord* addr)
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<region_sz_t>(live_obj_size());
const region_sz_t old = Atomic::cmpxchg(dc_claimed | los, &_dc_and_los, los);
return old == los;
}

View File

@ -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 @@ bool SubTasksDone::is_task_claimed(uint t) {
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 @@ bool SubTasksDone::is_task_claimed(uint t) {
}
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::valid() {
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;

View File

@ -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<T> 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<typename T>
struct IsRegisteredEnum : public FalseType {};
#endif // SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP

View File

@ -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_PRIMITIVECONVERSIONS_HPP
#define SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_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 PrimitiveConversions : 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<typename T, typename U> 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<typename T> struct Translate : public FalseType {};
private:
template<typename T,
typename U,
bool same_size = sizeof(T) == sizeof(U),
typename Enable = void>
struct Cast;
template<typename T, typename U> 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 <type_traits> 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<typename T, typename U>
inline T PrimitiveConversions::cast_using_union(U x) {
STATIC_ASSERT(sizeof(T) == sizeof(U));
union { T t; U u; };
u = x;
return t;
}
//////////////////////////////////////////////////////////////////////////////
// cast<T>(x)
//
// Cast<T, U, same_size, Enable>
// Give an informative error if the sizes differ.
template<typename T, typename U>
struct PrimitiveConversions::Cast<T, U, false> VALUE_OBJ_CLASS_SPEC {
STATIC_ASSERT(sizeof(T) == sizeof(U));
};
// Conversion between integral types.
template<typename T, typename U>
struct PrimitiveConversions::Cast<
T, U, true,
typename EnableIf<IsIntegral<T>::value && IsIntegral<U>::value>::type>
VALUE_OBJ_CLASS_SPEC
{
T operator()(U x) const { return cast_using_union<T>(x); }
};
// Convert an enum or floating point value to an integer value.
template<typename T, typename U>
struct PrimitiveConversions::Cast<
T, U, true,
typename EnableIf<IsIntegral<T>::value &&
(IsRegisteredEnum<U>::value ||
IsFloatingPoint<U>::value)>::type>
VALUE_OBJ_CLASS_SPEC
{
T operator()(U x) const { return cast_using_union<T>(x); }
};
// Convert an integer to an enum or floating point value.
template<typename T, typename U>
struct PrimitiveConversions::Cast<
T, U, true,
typename EnableIf<IsIntegral<U>::value &&
(IsRegisteredEnum<T>::value ||
IsFloatingPoint<T>::value)>::type>
VALUE_OBJ_CLASS_SPEC
{
T operator()(U x) const { return cast_using_union<T>(x); }
};
// Convert a pointer to an integral value.
template<typename T, typename U>
struct PrimitiveConversions::Cast<
T, U*, true,
typename EnableIf<IsIntegral<T>::value>::type>
VALUE_OBJ_CLASS_SPEC
{
T operator()(U* x) const { return reinterpret_cast<T>(x); }
};
// Convert an integral value to a pointer.
template<typename T, typename U>
struct PrimitiveConversions::Cast<
T*, U, true,
typename EnableIf<IsIntegral<U>::value>::type>
VALUE_OBJ_CLASS_SPEC
{
T* operator()(U x) const { return reinterpret_cast<T*>(x); }
};
template<typename T, typename U>
inline T PrimitiveConversions::cast(U x) {
return Cast<T, U>()(x);
}
#endif // SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP

View File

@ -94,7 +94,7 @@ void oopDesc::release_set_mark(markOop m) {
}
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 @@ oop oopDesc::atomic_compare_exchange_oop(oop exchange_value,
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);
}
}
@ -619,7 +619,7 @@ oop oopDesc::forward_to_atomic(oop p) {
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;

View File

@ -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/integralConstant.hpp"
#include "metaprogramming/primitiveConversions.hpp"
#include "runtime/globals.hpp"
#include "utilities/globalDefinitions.hpp"
@ -142,6 +144,15 @@ public:
operator oop* () const { return (oop *)obj(); }
};
template<>
struct PrimitiveConversions::Translate<oop> : 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 { \

View File

@ -26,6 +26,11 @@
#define SHARE_VM_RUNTIME_ATOMIC_HPP
#include "memory/allocation.hpp"
#include "metaprogramming/enableIf.hpp"
#include "metaprogramming/isIntegral.hpp"
#include "metaprogramming/isSame.hpp"
#include "metaprogramming/primitiveConversions.hpp"
#include "metaprogramming/removeCV.hpp"
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
@ -111,13 +116,132 @@ class Atomic : AllStatic {
// *dest with exchange_value if the comparison succeeded. Returns prior
// value of *dest. cmpxchg*() provide:
// <fence> compare-and-exchange <membar StoreLoad|StoreStore>
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<typename T, typename D, typename U>
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<typename T, typename D>
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<void* volatile*>(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<typename From, typename To> 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<typename T, typename D, typename U, typename Enable = void>
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<sizeof(T)>.
//
// 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<size_t byte_size> 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<typename Type, typename Fn, typename T>
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<typename From, typename To>
struct Atomic::IsPointerConvertible<From*, To*> : 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<size_t byte_size>
struct Atomic::PlatformCmpxchg VALUE_OBJ_CLASS_SPEC {
template<typename T>
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<typename T>
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 @@ inline void Atomic::dec(volatile size_t* dest) {
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<volatile jint*>(align_down(dest, sizeof(jint)));
size_t offset = pointer_delta(dest, dest_int, 1);
jint cur = *dest_int;
jbyte* cur_as_bytes = reinterpret_cast<jbyte*>(&cur);
template<typename T, typename D, typename U>
inline D Atomic::cmpxchg(T exchange_value,
D volatile* dest,
U compare_value,
cmpxchg_memory_order order) {
return CmpxchgImpl<T, D, U>()(exchange_value, dest, compare_value, order);
}
template<typename T, typename D>
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<typename T>
struct Atomic::CmpxchgImpl<
T, T, T,
typename EnableIf<IsIntegral<T>::value || IsRegisteredEnum<T>::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<sizeof(T)>()(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<typename T, typename D, typename U>
struct Atomic::CmpxchgImpl<
T*, D*, U*,
typename EnableIf<Atomic::IsPointerConvertible<T*, D*>::value &&
IsSame<typename RemoveCV<D>::type,
typename RemoveCV<U>::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<D*>(compare_value);
return PlatformCmpxchg<sizeof(D*)>()(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<typename T>
struct Atomic::CmpxchgImpl<
T, T, T,
typename EnableIf<PrimitiveConversions::Translate<T>::value>::type>
VALUE_OBJ_CLASS_SPEC
{
T operator()(T exchange_value, T volatile* dest, T compare_value,
cmpxchg_memory_order order) const {
typedef PrimitiveConversions::Translate<T> Translator;
typedef typename Translator::Decayed Decayed;
STATIC_ASSERT(sizeof(T) == sizeof(Decayed));
return Translator::recover(
cmpxchg(Translator::decay(exchange_value),
reinterpret_cast<Decayed volatile*>(dest),
Translator::decay(compare_value),
order));
}
};
template<typename Type, typename Fn, typename T>
inline T Atomic::cmpxchg_using_helper(Fn fn,
T exchange_value,
T volatile* dest,
T compare_value) {
STATIC_ASSERT(sizeof(Type) == sizeof(T));
return PrimitiveConversions::cast<T>(
fn(PrimitiveConversions::cast<Type>(exchange_value),
reinterpret_cast<Type volatile*>(dest),
PrimitiveConversions::cast<Type>(compare_value)));
}
template<typename T>
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<volatile uint32_t*>(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<uint8_t*>(&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<jbyte*>(&new_value)[offset] = exchange_value;
reinterpret_cast<uint8_t*>(&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 PrimitiveConversions::cast<T>(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

View File

@ -755,9 +755,9 @@ int os::random() {
// 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<int>(rand);
}
}
}

View File

@ -210,12 +210,12 @@ void BitMap::par_put_range_within_word(idx_t beg, idx_t end, bool value) {
// 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 @@ bool BitMap::iterate(BitMapClosure* blk, idx_t leftOffset, idx_t rightOffset) {
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 @@ void BitMap::init_pop_count_table() {
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);
}
}

View File

@ -114,7 +114,7 @@ class BitMap VALUE_OBJ_CLASS_SPEC {
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);

View File

@ -49,9 +49,7 @@ inline bool BitMap::par_set_bit(idx_t bit) {
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 @@ inline bool BitMap::par_clear_bit(idx_t bit) {
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.
}

View File

@ -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<A> : public TrueType {};
STATIC_ASSERT(!IsRegisteredEnum<int>::value);
STATIC_ASSERT(IsRegisteredEnum<A>::value);
STATIC_ASSERT(!IsRegisteredEnum<B>::value);

View File

@ -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/isSame.hpp"
#include "metaprogramming/primitiveConversions.hpp"
#include "unittest.hpp"
#include "utilities/debug.hpp"
struct PrimitiveConversionsTestSupport: AllStatic {
template<size_t byte_size> struct SignedTypeOfSize;
template<size_t byte_size> struct UnsignedTypeOfSize;
template<typename T> struct Signed;
template<typename T> struct Unsigned;
};
#define DEFINE_CANONICAL_SIGNED_TYPE(T) \
template<> \
struct PrimitiveConversionsTestSupport::SignedTypeOfSize<sizeof(T)> \
: public AllStatic \
{ \
typedef T type; \
};
#define DEFINE_CANONICAL_UNSIGNED_TYPE(T) \
template<> \
struct PrimitiveConversionsTestSupport::UnsignedTypeOfSize<sizeof(T)> \
: 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<typename T>
struct PrimitiveConversionsTestSupport::Signed
: public SignedTypeOfSize<sizeof(T)>
{};
template<typename T>
struct PrimitiveConversionsTestSupport::Unsigned
: public UnsignedTypeOfSize<sizeof(T)>
{};
TEST(PrimitiveConversionsTest, round_trip_int) {
int sfive = 5;
int mfive = -5;
uint ufive = 5u;
typedef PrimitiveConversionsTestSupport::Signed<int>::type SI;
typedef PrimitiveConversionsTestSupport::Unsigned<int>::type UI;
EXPECT_EQ(sfive, PrimitiveConversions::cast<int>(PrimitiveConversions::cast<SI>(sfive)));
EXPECT_EQ(sfive, PrimitiveConversions::cast<int>(PrimitiveConversions::cast<UI>(sfive)));
EXPECT_EQ(mfive, PrimitiveConversions::cast<int>(PrimitiveConversions::cast<SI>(mfive)));
EXPECT_EQ(mfive, PrimitiveConversions::cast<int>(PrimitiveConversions::cast<UI>(mfive)));
EXPECT_EQ(ufive, PrimitiveConversions::cast<uint>(PrimitiveConversions::cast<SI>(ufive)));
EXPECT_EQ(ufive, PrimitiveConversions::cast<uint>(PrimitiveConversions::cast<UI>(ufive)));
}
TEST(PrimitiveConversionsTest, round_trip_float) {
float ffive = 5.0f;
double dfive = 5.0;
typedef PrimitiveConversionsTestSupport::Signed<float>::type SF;
typedef PrimitiveConversionsTestSupport::Unsigned<float>::type UF;
typedef PrimitiveConversionsTestSupport::Signed<double>::type SD;
typedef PrimitiveConversionsTestSupport::Unsigned<double>::type UD;
EXPECT_EQ(ffive, PrimitiveConversions::cast<float>(PrimitiveConversions::cast<SF>(ffive)));
EXPECT_EQ(ffive, PrimitiveConversions::cast<float>(PrimitiveConversions::cast<UF>(ffive)));
EXPECT_EQ(dfive, PrimitiveConversions::cast<double>(PrimitiveConversions::cast<SD>(dfive)));
EXPECT_EQ(dfive, PrimitiveConversions::cast<double>(PrimitiveConversions::cast<UD>(dfive)));
}
TEST(PrimitiveConversionsTest, round_trip_ptr) {
int five = 5;
int* pfive = &five;
const int* cpfive = &five;
typedef PrimitiveConversionsTestSupport::Signed<int*>::type SIP;
typedef PrimitiveConversionsTestSupport::Unsigned<int*>::type UIP;
EXPECT_EQ(pfive, PrimitiveConversions::cast<int*>(PrimitiveConversions::cast<SIP>(pfive)));
EXPECT_EQ(pfive, PrimitiveConversions::cast<int*>(PrimitiveConversions::cast<UIP>(pfive)));
EXPECT_EQ(cpfive, PrimitiveConversions::cast<const int*>(PrimitiveConversions::cast<SIP>(cpfive)));
EXPECT_EQ(cpfive, PrimitiveConversions::cast<const int*>(PrimitiveConversions::cast<UIP>(cpfive)));
}