Bug 1146817 - Add float and double test cases for loadSafeWhenRacy / storeSafeWhenRacy. r=sstangl
authorLars T Hansen <lhansen@mozilla.com>
Tue, 05 Sep 2017 13:48:53 +0200
changeset 428776 b62fb112ddd892522f4cfc737fcf4ce4568b64c1
parent 428775 43cf87ac46c7c81e73541c7687726406806a584e
child 428777 0be76a0e23a2b3df6be30b4c0cce6b0b94fb367d
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)
reviewerssstangl
bugs1146817
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 1146817 - Add float and double test cases for loadSafeWhenRacy / storeSafeWhenRacy. r=sstangl
js/src/jit/AtomicOperations.h
js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
js/src/jsapi-tests/testAtomicOperations.cpp
--- a/js/src/jit/AtomicOperations.h
+++ b/js/src/jit/AtomicOperations.h
@@ -135,20 +135,20 @@ class AtomicOperations
     template<typename T>
     static inline T loadSafeWhenRacy(T* addr);
 
     // Defined for all the integral types as well as for float32 and float64,
     // but not access-atomic for floats.
     template<typename T>
     static inline void storeSafeWhenRacy(T* addr, T val);
 
-    // Replacement for memcpy().
+    // Replacement for memcpy().  No access-atomicity guarantees.
     static inline void memcpySafeWhenRacy(void* dest, const void* src, size_t nbytes);
 
-    // Replacement for memmove().
+    // Replacement for memmove().  No access-atomicity guarantees.
     static inline void memmoveSafeWhenRacy(void* dest, const void* src, size_t nbytes);
 
   public:
     // Test lock-freedom for any int32 value.  This implements the
     // Atomics::isLockFree() operation in the ECMAScript Shared Memory and
     // Atomics specification, as follows:
     //
     // 4-byte accesses are always lock free (in the spec).
@@ -282,29 +282,28 @@ class AtomicOperations
     tier1Constraints(const T* addr) {
         static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
         return (sizeof(T) < 8 || (hasAtomic8() && isLockfree8())) &&
                !(uintptr_t(addr) & (sizeof(T) - 1));
     }
 #endif
 };
 
-/* A data type representing a lock on some region of a
- * SharedArrayRawBuffer's memory, to be used only when the hardware
- * does not provide necessary atomicity (eg, float64 access on ARMv6
- * and some ARMv7 systems).
+/* A data type representing a lock on some region of a SharedArrayRawBuffer's
+ * memory, to be used only when the hardware does not provide necessary
+ * atomicity.
  */
 class RegionLock
 {
   public:
     RegionLock() : spinlock(0) {}
 
     /* Addr is the address to be locked, nbytes the number of bytes we
      * need to lock.  The lock that is taken may cover a larger range
-     * of bytes.
+     * of bytes, indeed it may cover all of memory.
      */
     template<size_t nbytes>
     void acquire(void* addr);
 
     /* Addr is the address to be unlocked, nbytes the number of bytes
      * we need to unlock.  The lock must be held by the calling thread,
      * at the given address and for the number of bytes.
      */
--- a/js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
+++ b/js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
@@ -349,16 +349,18 @@ js::jit::AtomicOperations::loadSafeWhenR
     inline T                                      \
     AtomicOperations::loadSafeWhenRacy(T* addr) { \
         MOZ_ASSERT(tier1Constraints(addr));       \
         return (T)_InterlockedCompareExchange64((__int64 volatile*)addr, 0, 0); \
     }
 
 namespace js { namespace jit {
 
+// For double and float there are no access-atomicity guarantees so go directly
+// to the default implementation.
 MSC_RACYLOADOP(int64_t)
 MSC_RACYLOADOP(uint64_t)
 
 } }
 
 # undef MSC_RACYLOADOP
 #endif // _M_IX86
 
@@ -384,16 +386,18 @@ namespace js { namespace jit {
                                                          (__int64)val,            \
                                                          (__int64)oldval);        \
             if (nextval == oldval)                        \
                 break;                                    \
             oldval = nextval;                             \
         }                                                 \
     }
 
+// For double and float there are no access-atomicity guarantees so go directly
+// to the default implementation.
 MSC_RACYSTOREOP(int64_t)
 MSC_RACYSTOREOP(uint64_t)
 
 # undef MSC_STOREOP
 
 } }
 #endif // _M_IX86
 
--- a/js/src/jsapi-tests/testAtomicOperations.cpp
+++ b/js/src/jsapi-tests/testAtomicOperations.cpp
@@ -222,9 +222,86 @@ BEGIN_TEST(testAtomicOperationsI64)
         return true;
 
     const int64_t A(0x2aadf00ddeadbeef);
     const int64_t B(0x4eedbead1337f001);
     ATOMIC_TESTS(int64_t, A, B);
 }
 END_TEST(testAtomicOperationsI64)
 
+// T is the primitive float type we're testing, and A and B are references to
+// constant bindings holding values of that type.
+//
+// Stay away from 0, NaN, infinities, and denormals.
+
+#define ATOMIC_FLOAT_TESTS(T, A, B) \
+    T* q = (T*)hidePointerValue((void*)atomicMem);                      \
+    *q = A;                                                             \
+    SharedMem<T*> p = SharedMem<T*>::shared((T*)hidePointerValue((T*)atomicMem)); \
+    CHECK(*q == A);                                                     \
+    CHECK(jit::AtomicOperations::loadSafeWhenRacy(p) == A);             \
+    jit::AtomicOperations::storeSafeWhenRacy(p, B);                     \
+    CHECK(*q == B);                                                     \
+    T* q2 = (T*)hidePointerValue((void*)atomicMem2);                    \
+    SharedMem<T*> p2 = SharedMem<T*>::shared((T*)hidePointerValue((void*)atomicMem2)); \
+    *q = A;                                                             \
+    *q2 = B;                                                            \
+    jit::AtomicOperations::memcpySafeWhenRacy(p2, p, sizeof(T));        \
+    CHECK(*q2 == A);                                                    \
+    *q = A;                                                             \
+    *q2 = B;                                                            \
+    jit::AtomicOperations::memcpySafeWhenRacy(p2, p.unwrap(), sizeof(T));\
+    CHECK(*q2 == A);                                                    \
+    *q = A;                                                             \
+    *q2 = B;                                                            \
+    jit::AtomicOperations::memcpySafeWhenRacy(p2.unwrap(), p, sizeof(T));\
+    CHECK(*q2 == A);                                                    \
+    *q = A;                                                             \
+    *q2 = B;                                                            \
+    jit::AtomicOperations::memmoveSafeWhenRacy(p2, p, sizeof(T));       \
+    CHECK(*q2 == A);                                                    \
+    *q = A;                                                             \
+    *q2 = B;                                                            \
+    jit::AtomicOperations::podCopySafeWhenRacy(p2, p, 1);               \
+    CHECK(*q2 == A);                                                    \
+    *q = A;                                                             \
+    *q2 = B;                                                            \
+    jit::AtomicOperations::podMoveSafeWhenRacy(p2, p, 1);               \
+    CHECK(*q2 == A);                                                    \
+    return true
+
+BEGIN_TEST(testAtomicOperationsF32)
+{
+    const float A(123.25);
+    const float B(-987.75);
+    ATOMIC_FLOAT_TESTS(float, A, B);
+}
+END_TEST(testAtomicOperationsF32)
+
+BEGIN_TEST(testAtomicOperationsF64)
+{
+    const double A(123.25);
+    const double B(-987.75);
+    ATOMIC_FLOAT_TESTS(double, A, B);
+}
+END_TEST(testAtomicOperationsF64)
+
+#define ATOMIC_CLAMPED_TESTS(T, A, B) \
+    T* q = (T*)hidePointerValue((void*)atomicMem);                      \
+    *q = A;                                                             \
+    SharedMem<T*> p = SharedMem<T*>::shared((T*)hidePointerValue((T*)atomicMem)); \
+    CHECK(*q == A);                                                     \
+    CHECK(jit::AtomicOperations::loadSafeWhenRacy(p) == A);             \
+    jit::AtomicOperations::storeSafeWhenRacy(p, B);                     \
+    CHECK(*q == B);                                                     \
+    return true
+
+BEGIN_TEST(testAtomicOperationsU8Clamped)
+{
+    const uint8_clamped A(0xab);
+    const uint8_clamped B(0x37);
+    ATOMIC_CLAMPED_TESTS(uint8_clamped, A, B);
+}
+END_TEST(testAtomicOperationsU8Clamped)
+
 #undef ATOMIC_TESTS
+#undef ATOMIC_FLOAT_TESTS
+#undef ATOMIC_CLAMPED_TESTS