Bug 1399516 - Enable 64-bit atomics on MIPS and minor code cleanup. r=lth
authorDragan Mladjenovic <dragan.mladjenovic@rt-rk.com>
Wed, 13 Sep 2017 08:26:00 -0400
changeset 430300 9d77baa08ebf684c4775211f8bda2acc266d2fe8
parent 430299 3a35599c5d1e44c9787aa93b2b0cb41e13f4b7be
child 430301 a88de77074283143e5c9c6b7cfc7d66621034832
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1399516
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1399516 - Enable 64-bit atomics on MIPS and minor code cleanup. r=lth
js/src/jit/mips-shared/AtomicOperations-mips-shared.h
--- a/js/src/jit/mips-shared/AtomicOperations-mips-shared.h
+++ b/js/src/jit/mips-shared/AtomicOperations-mips-shared.h
@@ -6,193 +6,203 @@
 
 /* For documentation, see jit/AtomicOperations.h */
 
 // NOTE, this file is *not* used with the MIPS simulator, only when compiling
 // for actual MIPS hardware.  The simulators get the files that are appropriate
 // for the hardware the simulator is running on.  See the comments before the
 // #include nest at the bottom of jit/AtomicOperations.h for more information.
 
+// NOTE, MIPS32 unlike MIPS64 doesn't provide hardware support for lock-free
+// 64-bit atomics. We lie down below about 8-byte atomics being always lock-
+// free in order to support wasm jit. It is necessary to link with -latomic to
+// get the 64-bit atomic intrinsics on MIPS32.
+
 #ifndef jit_mips_shared_AtomicOperations_mips_shared_h
 #define jit_mips_shared_AtomicOperations_mips_shared_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Types.h"
 
+#include "vm/ArrayBufferObject.h"
+
 #if !defined(__clang__) && !defined(__GNUC__)
 # error "This file only for gcc-compatible compilers"
 #endif
 
-// The default implementation tactic for gcc/clang is to use the newer
-// __atomic intrinsics added for use in C++11 <atomic>.  Where that
-// isn't available, we use GCC's older __sync functions instead.
-//
-// ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS is kept as a backward
-// compatible option for older compilers: enable this to use GCC's old
-// __sync functions instead of the newer __atomic functions.  This
-// will be required for GCC 4.6.x and earlier, and probably for Clang
-// 3.1, should we need to use those versions.
-
-//#define ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-
 inline bool
 js::jit::AtomicOperations::hasAtomic8()
 {
-    // NOTE, change this when primitives below have been properly changed to
-    // support 8-byte atomics.
-    return false;
+    return true;
 }
 
 inline bool
 js::jit::AtomicOperations::isLockfree8()
 {
-    if (!hasAtomic8())
-        return false;
-
-#ifndef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
     MOZ_ASSERT(__atomic_always_lock_free(sizeof(int8_t), 0));
     MOZ_ASSERT(__atomic_always_lock_free(sizeof(int16_t), 0));
     MOZ_ASSERT(__atomic_always_lock_free(sizeof(int32_t), 0));
-    // NOTE, this condition is obsolete.  See comment above.
 # if _MIPS_SIM == _ABI64
     MOZ_ASSERT(__atomic_always_lock_free(sizeof(int64_t), 0));
 # endif
     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)
 {
-    MOZ_ASSERT(sizeof(T) < 8 || isLockfree8());
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    __sync_synchronize();
-    T v = *addr;
-    __sync_synchronize();
-#else
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
     T v;
     __atomic_load(addr, &v, __ATOMIC_SEQ_CST);
-#endif
     return v;
 }
 
 template<typename T>
 inline void
 js::jit::AtomicOperations::storeSeqCst(T* addr, T val)
 {
-    MOZ_ASSERT(sizeof(T) < 8 || isLockfree8());
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    __sync_synchronize();
-    *addr = val;
-    __sync_synchronize();
-#else
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
     __atomic_store(addr, &val, __ATOMIC_SEQ_CST);
-#endif
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval, T newval)
 {
-    MOZ_ASSERT(sizeof(T) < 8 || isLockfree8());
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    return __sync_val_compare_and_swap(addr, oldval, newval);
-#else
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
     __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
     return oldval;
-#endif
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::fetchAddSeqCst(T* addr, T val)
 {
-    static_assert(sizeof(T) <= 4, "not available for 8-byte values yet");
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    return __sync_fetch_and_add(addr, val);
-#else
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
     return __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST);
-#endif
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::fetchSubSeqCst(T* addr, T val)
 {
-    static_assert(sizeof(T) <= 4, "not available for 8-byte values yet");
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    return __sync_fetch_and_sub(addr, val);
-#else
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
     return __atomic_fetch_sub(addr, val, __ATOMIC_SEQ_CST);
-#endif
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::fetchAndSeqCst(T* addr, T val)
 {
-    static_assert(sizeof(T) <= 4, "not available for 8-byte values yet");
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    return __sync_fetch_and_and(addr, val);
-#else
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
     return __atomic_fetch_and(addr, val, __ATOMIC_SEQ_CST);
-#endif
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::fetchOrSeqCst(T* addr, T val)
 {
-    static_assert(sizeof(T) <= 4, "not available for 8-byte values yet");
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    return __sync_fetch_and_or(addr, val);
-#else
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
     return __atomic_fetch_or(addr, val, __ATOMIC_SEQ_CST);
-#endif
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::fetchXorSeqCst(T* addr, T val)
 {
-    static_assert(sizeof(T) <= 4, "not available for 8-byte values yet");
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    return __sync_fetch_and_xor(addr, val);
-#else
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
     return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
-#endif
+
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::loadSafeWhenRacy(T* addr)
 {
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
+    if (__atomic_always_lock_free(sizeof(T), 0)) {
+        T v;
+        __atomic_load(addr, &v, __ATOMIC_RELAXED);
+        return v;
+    } else {
+        return *addr;
+    }
+}
+
+namespace js { namespace jit {
+
+template<>
+inline uint8_clamped
+js::jit::AtomicOperations::loadSafeWhenRacy(uint8_clamped* addr)
+{
+    uint8_t v;
+    __atomic_load(&addr->val, &v, __ATOMIC_RELAXED);
+    return uint8_clamped(v);
+}
+
+template<>
+inline float
+js::jit::AtomicOperations::loadSafeWhenRacy(float* addr)
+{
     return *addr;
 }
 
+template<>
+inline double
+js::jit::AtomicOperations::loadSafeWhenRacy(double* addr)
+{
+    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");
+    if (__atomic_always_lock_free(sizeof(T), 0)) {
+        __atomic_store(addr, &val, __ATOMIC_RELAXED);
+    } else {
+        *addr = val;
+    }
+}
+
+namespace js { namespace jit {
+
+template<>
+inline void
+js::jit::AtomicOperations::storeSafeWhenRacy(uint8_clamped* addr, uint8_clamped val)
+{
+    __atomic_store(&addr->val, &val.val, __ATOMIC_RELAXED);
+}
+
+template<>
+inline void
+js::jit::AtomicOperations::storeSafeWhenRacy(float* addr, float val)
+{
     *addr = val;
 }
 
+template<>
+inline void
+js::jit::AtomicOperations::storeSafeWhenRacy(double* addr, double val)
+{
+    *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);
 }
 
@@ -201,56 +211,37 @@ js::jit::AtomicOperations::memmoveSafeWh
 {
     ::memmove(dest, src, nbytes);
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val)
 {
-    MOZ_ASSERT(sizeof(T) < 8 || isLockfree8());
-#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
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
     T v;
     __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
     return v;
-#endif
 }
 
 template<size_t nbytes>
 inline void
 js::jit::RegionLock::acquire(void* addr)
 {
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    while (!__sync_bool_compare_and_swap(&spinlock, 0, 1))
-        ;
-#else
     uint32_t zero = 0;
     uint32_t one = 1;
     while (!__atomic_compare_exchange(&spinlock, &zero, &one, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) {
         zero = 0;
         continue;
     }
-#endif
 }
 
 template<size_t nbytes>
 inline void
 js::jit::RegionLock::release(void* addr)
 {
     MOZ_ASSERT(AtomicOperations::loadSeqCst(&spinlock) == 1, "releasing unlocked region lock");
-#ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-    __sync_sub_and_fetch(&spinlock, 1);
-#else
     uint32_t zero = 0;
     __atomic_store(&spinlock, &zero, __ATOMIC_SEQ_CST);
-#endif
 }
 
-#undef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
 
 #endif // jit_mips_shared_AtomicOperations_mips_shared_h