mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-27 13:52:27 +00:00
8186166: Generalize Atomic::cmpxchg with templates
Reviewed-by: dholmes, coleenp
This commit is contained in:
parent
61a9f88ca7
commit
e54adefc2f
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
42
hotspot/src/share/vm/metaprogramming/isRegisteredEnum.hpp
Normal file
42
hotspot/src/share/vm/metaprogramming/isRegisteredEnum.hpp
Normal 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
|
||||
|
||||
170
hotspot/src/share/vm/metaprogramming/primitiveConversions.hpp
Normal file
170
hotspot/src/share/vm/metaprogramming/primitiveConversions.hpp
Normal 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
|
||||
@ -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;
|
||||
|
||||
@ -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 { \
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
}
|
||||
|
||||
@ -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);
|
||||
@ -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)));
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user