#ifndef jit_shared_AtomicOperations_feeling_lucky_gcc_h
#define jit_shared_AtomicOperations_feeling_lucky_gcc_h
#include "mozilla/Assertions.h"
#include "mozilla/Types.h"
#if ((defined(__x86_64__) || defined(_M_X64)) && defined(JS_CODEGEN_X64)) || \
((defined(__i386__) || defined(_M_IX86)) && defined(JS_CODEGEN_X86)) || \
(defined(__arm__) && defined(JS_CODEGEN_ARM)) || \
((defined(__aarch64__) || defined(_M_ARM64)) && defined(JS_CODEGEN_ARM64))
# error "Do not use this code on a tier-1 platform when a JIT is available"
#endif
#if !(defined(__clang__) || defined(__GNUC__))
# error "This file only for gcc/Clang"
#endif
#if defined(JS_SIMULATOR_ARM64) || defined(JS_SIMULATOR_ARM)
# define HAS_64BIT_ATOMICS
# define HAS_64BIT_LOCKFREE
#endif
#if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \
defined(__PPC64LE__)
# define HAS_64BIT_ATOMICS
# define HAS_64BIT_LOCKFREE
#endif
#ifdef __sparc__
# ifdef __LP64__
# define HAS_64BIT_ATOMICS
# define HAS_64BIT_LOCKFREE
# endif
#endif
#if defined(HAS_64BIT_LOCKFREE) && !defined(HAS_64BIT_ATOMICS)
# error "This combination of features is senseless, please fix"
#endif
inline bool js::jit::AtomicOperations::Initialize() {
return true;
}
inline void js::jit::AtomicOperations::ShutDown() {
}
inline bool js::jit::AtomicOperations::hasAtomic8() {
#if defined(HAS_64BIT_ATOMICS)
return true;
#else
return false;
#endif
}
inline bool js::jit::AtomicOperations::isLockfree8() {
#if defined(HAS_64BIT_LOCKFREE)
return true;
#else
return false;
#endif
}
inline void js::jit::AtomicOperations::fenceSeqCst() {
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
__sync_synchronize();
#else
__atomic_thread_fence(__ATOMIC_SEQ_CST);
#endif
}
template <typename T>
inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
__sync_synchronize();
T v = *addr;
__sync_synchronize();
#else
T v;
__atomic_load(addr, &v, __ATOMIC_SEQ_CST);
#endif
return v;
}
#ifndef HAS_64BIT_ATOMICS
namespace js {
namespace jit {
template <>
inline int64_t AtomicOperations::loadSeqCst(int64_t* addr) {
MOZ_CRASH("No 64-bit atomics");
}
template <>
inline uint64_t AtomicOperations::loadSeqCst(uint64_t* addr) {
MOZ_CRASH("No 64-bit atomics");
}
} } #endif
template <typename T>
inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
__sync_synchronize();
*addr = val;
__sync_synchronize();
#else
__atomic_store(addr, &val, __ATOMIC_SEQ_CST);
#endif
}
#ifndef HAS_64BIT_ATOMICS
namespace js {
namespace jit {
template <>
inline void AtomicOperations::storeSeqCst(int64_t* addr, int64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
template <>
inline void AtomicOperations::storeSeqCst(uint64_t* addr, uint64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
} } #endif
template <typename T>
inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
T v;
__sync_synchronize();
do {
v = *addr;
} while (__sync_val_compare_and_swap(addr, v, val) != v);
return v;
#else
T v;
__atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
return v;
#endif
}
#ifndef HAS_64BIT_ATOMICS
namespace js {
namespace jit {
template <>
inline int64_t AtomicOperations::exchangeSeqCst(int64_t* addr, int64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
template <>
inline uint64_t AtomicOperations::exchangeSeqCst(uint64_t* addr, uint64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
} } #endif
template <typename T>
inline T js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval,
T newval) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
return __sync_val_compare_and_swap(addr, oldval, newval);
#else
__atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST,
__ATOMIC_SEQ_CST);
return oldval;
#endif
}
#ifndef HAS_64BIT_ATOMICS
namespace js {
namespace jit {
template <>
inline int64_t AtomicOperations::compareExchangeSeqCst(int64_t* addr,
int64_t oldval,
int64_t newval) {
MOZ_CRASH("No 64-bit atomics");
}
template <>
inline uint64_t AtomicOperations::compareExchangeSeqCst(uint64_t* addr,
uint64_t oldval,
uint64_t newval) {
MOZ_CRASH("No 64-bit atomics");
}
} } #endif
template <typename T>
inline T js::jit::AtomicOperations::fetchAddSeqCst(T* addr, T val) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
return __sync_fetch_and_add(addr, val);
#else
return __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST);
#endif
}
#ifndef HAS_64BIT_ATOMICS
namespace js {
namespace jit {
template <>
inline int64_t AtomicOperations::fetchAddSeqCst(int64_t* addr, int64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
template <>
inline uint64_t AtomicOperations::fetchAddSeqCst(uint64_t* addr, uint64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
} } #endif
template <typename T>
inline T js::jit::AtomicOperations::fetchSubSeqCst(T* addr, T val) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
return __sync_fetch_and_sub(addr, val);
#else
return __atomic_fetch_sub(addr, val, __ATOMIC_SEQ_CST);
#endif
}
#ifndef HAS_64BIT_ATOMICS
namespace js {
namespace jit {
template <>
inline int64_t AtomicOperations::fetchSubSeqCst(int64_t* addr, int64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
template <>
inline uint64_t AtomicOperations::fetchSubSeqCst(uint64_t* addr, uint64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
} } #endif
template <typename T>
inline T js::jit::AtomicOperations::fetchAndSeqCst(T* addr, T val) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
return __sync_fetch_and_and(addr, val);
#else
return __atomic_fetch_and(addr, val, __ATOMIC_SEQ_CST);
#endif
}
#ifndef HAS_64BIT_ATOMICS
namespace js {
namespace jit {
template <>
inline int64_t AtomicOperations::fetchAndSeqCst(int64_t* addr, int64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
template <>
inline uint64_t AtomicOperations::fetchAndSeqCst(uint64_t* addr, uint64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
} } #endif
template <typename T>
inline T js::jit::AtomicOperations::fetchOrSeqCst(T* addr, T val) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
return __sync_fetch_and_or(addr, val);
#else
return __atomic_fetch_or(addr, val, __ATOMIC_SEQ_CST);
#endif
}
#ifndef HAS_64BIT_ATOMICS
namespace js {
namespace jit {
template <>
inline int64_t AtomicOperations::fetchOrSeqCst(int64_t* addr, int64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
template <>
inline uint64_t AtomicOperations::fetchOrSeqCst(uint64_t* addr, uint64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
} } #endif
template <typename T>
inline T js::jit::AtomicOperations::fetchXorSeqCst(T* addr, T val) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
return __sync_fetch_and_xor(addr, val);
#else
return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
#endif
}
#ifndef HAS_64BIT_ATOMICS
namespace js {
namespace jit {
template <>
inline int64_t AtomicOperations::fetchXorSeqCst(int64_t* addr, int64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
template <>
inline uint64_t AtomicOperations::fetchXorSeqCst(uint64_t* addr, uint64_t val) {
MOZ_CRASH("No 64-bit atomics");
}
} } #endif
template <typename T>
inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
return *addr;
}
template <typename T>
inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
*addr = val;
}
inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
const void* src,
size_t nbytes) {
MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
::memcpy(dest, src, nbytes);
}
inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
const void* src,
size_t nbytes) {
::memmove(dest, src, nbytes);
}
#undef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
#undef HAS_64BIT_ATOMICS
#undef HAS_64BIT_LOCKFREE
#endif