8157152: Atomic add for VarHandle byte[]/ByteBuffer views is incorrect for endian conversion
authorpsandoz
Wed, 18 May 2016 18:46:14 +0200
changeset 38382 98d5a441bc2f
parent 38381 a2105ea409ec
child 38417 07152c7004b0
8157152: Atomic add for VarHandle byte[]/ByteBuffer views is incorrect for endian conversion Reviewed-by: fyuan, shade, vlivanov
jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template
jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java
jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java
jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java
jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java
jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java
jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java
jdk/test/java/lang/invoke/VarHandles/generate-vh-tests.sh
--- a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template	Wed May 18 16:39:08 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template	Wed May 18 18:46:14 2016 +0200
@@ -271,22 +271,33 @@
 #if[AtomicAdd]
 
         @ForceInline
-        static $type$ getAndAdd(ArrayHandle handle, Object oba, int index, $type$ value) {
+        static $type$ getAndAdd(ArrayHandle handle, Object oba, int index, $type$ delta) {
             byte[] ba = (byte[]) oba;
-            return convEndian(handle.be,
-                              UNSAFE.getAndAdd$RawType$(
-                                      ba,
-                                      address(ba, index(ba, index)),
-                                      convEndian(handle.be, value)));
+            if (handle.be == BE) {
+                return UNSAFE.getAndAdd$RawType$(
+                        ba,
+                        address(ba, index(ba, index)),
+                        delta);
+            } else {
+                return getAndAddConvEndianWithCAS(ba, index, delta);
+            }
         }
 
         @ForceInline
-        static $type$ addAndGet(ArrayHandle handle, Object oba, int index, $type$ value) {
-            byte[] ba = (byte[]) oba;
-            return convEndian(handle.be, UNSAFE.getAndAdd$RawType$(
-                    ba,
-                    address(ba, index(ba, index)),
-                    convEndian(handle.be, value))) + value;
+        static $type$ getAndAddConvEndianWithCAS(byte[] ba, int index, $type$ delta) {
+            $type$ nativeExpectedValue, expectedValue;
+            long offset = address(ba, index(ba, index));
+            do {
+                nativeExpectedValue = UNSAFE.get$RawType$Volatile(ba, offset);
+                expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
+            } while (!UNSAFE.weakCompareAndSwap$RawType$Volatile(ba, offset,
+                    nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta)));
+            return expectedValue;
+        }
+
+        @ForceInline
+        static $type$ addAndGet(ArrayHandle handle, Object oba, int index, $type$ delta) {
+            return getAndAdd(handle, oba, index, delta) + delta;
         }
 #end[AtomicAdd]
 
@@ -503,23 +514,34 @@
 #if[AtomicAdd]
 
         @ForceInline
-        static $type$ getAndAdd(ByteBufferHandle handle, Object obb, int index, $type$ value) {
+        static $type$ getAndAdd(ByteBufferHandle handle, Object obb, int index, $type$ delta) {
             ByteBuffer bb = (ByteBuffer) obb;
-            return convEndian(handle.be,
-                              UNSAFE.getAndAdd$RawType$(
-                                      UNSAFE.getObject(bb, BYTE_BUFFER_HB),
-                                      address(bb, indexRO(bb, index)),
-                                      convEndian(handle.be, value)));
+            if (handle.be == BE) {
+                return UNSAFE.getAndAdd$RawType$(
+                        UNSAFE.getObject(bb, BYTE_BUFFER_HB),
+                        address(bb, indexRO(bb, index)),
+                        delta);
+            } else {
+                return getAndAddConvEndianWithCAS(bb, index, delta);
+            }
         }
 
         @ForceInline
-        static $type$ addAndGet(ByteBufferHandle handle, Object obb, int index, $type$ value) {
-            ByteBuffer bb = (ByteBuffer) obb;
-            return convEndian(handle.be,
-                              UNSAFE.getAndAdd$RawType$(
-                                      UNSAFE.getObject(bb, BYTE_BUFFER_HB),
-                                      address(bb, indexRO(bb, index)),
-                                      convEndian(handle.be, value))) + value;
+        static $type$ getAndAddConvEndianWithCAS(ByteBuffer bb, int index, $type$ delta) {
+            $type$ nativeExpectedValue, expectedValue;
+            Object base = UNSAFE.getObject(bb, BYTE_BUFFER_HB);
+            long offset = address(bb, indexRO(bb, index));
+            do {
+                nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
+                expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
+            } while (!UNSAFE.weakCompareAndSwap$RawType$Volatile(base, offset,
+                    nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta)));
+            return expectedValue;
+        }
+
+        @ForceInline
+        static $type$ addAndGet(ByteBufferHandle handle, Object obb, int index, $type$ delta) {
+            return getAndAdd(handle, obb, index, delta) + delta;
         }
 #end[AtomicAdd]
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java	Wed May 18 16:39:08 2016 +0100
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java	Wed May 18 18:46:14 2016 +0200
@@ -51,7 +51,7 @@
 
     static final char VALUE_2 = (char)0x1112;
 
-    static final char VALUE_3 = (char)0x2122;
+    static final char VALUE_3 = (char)0xFFFE;
 
 
     @Override
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java	Wed May 18 16:39:08 2016 +0100
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java	Wed May 18 18:46:14 2016 +0200
@@ -51,7 +51,7 @@
 
     static final double VALUE_2 = 0x1112131415161718L;
 
-    static final double VALUE_3 = 0x2122232425262728L;
+    static final double VALUE_3 = 0xFFFEFDFCFBFAF9F8L;
 
 
     @Override
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java	Wed May 18 16:39:08 2016 +0100
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java	Wed May 18 18:46:14 2016 +0200
@@ -51,7 +51,7 @@
 
     static final float VALUE_2 = 0x11121314;
 
-    static final float VALUE_3 = 0x21222324;
+    static final float VALUE_3 = 0xFFFEFDFC;
 
 
     @Override
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java	Wed May 18 16:39:08 2016 +0100
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java	Wed May 18 18:46:14 2016 +0200
@@ -51,7 +51,7 @@
 
     static final int VALUE_2 = 0x11121314;
 
-    static final int VALUE_3 = 0x21222324;
+    static final int VALUE_3 = 0xFFFEFDFC;
 
 
     @Override
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java	Wed May 18 16:39:08 2016 +0100
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java	Wed May 18 18:46:14 2016 +0200
@@ -51,7 +51,7 @@
 
     static final long VALUE_2 = 0x1112131415161718L;
 
-    static final long VALUE_3 = 0x2122232425262728L;
+    static final long VALUE_3 = 0xFFFEFDFCFBFAF9F8L;
 
 
     @Override
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java	Wed May 18 16:39:08 2016 +0100
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java	Wed May 18 18:46:14 2016 +0200
@@ -51,7 +51,7 @@
 
     static final short VALUE_2 = (short)0x1112;
 
-    static final short VALUE_3 = (short)0x2122;
+    static final short VALUE_3 = (short)0xFFFE;
 
 
     @Override
--- a/jdk/test/java/lang/invoke/VarHandles/generate-vh-tests.sh	Wed May 18 16:39:08 2016 +0100
+++ b/jdk/test/java/lang/invoke/VarHandles/generate-vh-tests.sh	Wed May 18 18:46:14 2016 +0200
@@ -113,36 +113,40 @@
       ;;
   esac
 
+  # The value of `value3` is chosen such that when added to `value1` or `value2`
+  # it will result in carrying of bits over to the next byte, thereby detecting
+  # possible errors in endianness conversion e.g. if say for atomic addition the
+  # augend is incorrectly processed
   case $type in
     short)
       value1=(short)0x0102
       value2=(short)0x1112
-      value3=(short)0x2122
+      value3=(short)0xFFFE
       ;;
     char)
       value1=(char)0x0102
       value2=(char)0x1112
-      value3=(char)0x2122
+      value3=(char)0xFFFE
       ;;
     int)
       value1=0x01020304
       value2=0x11121314
-      value3=0x21222324
+      value3=0xFFFEFDFC
       ;;
     long)
       value1=0x0102030405060708L
       value2=0x1112131415161718L
-      value3=0x2122232425262728L
+      value3=0xFFFEFDFCFBFAF9F8L
       ;;
     float)
       value1=0x01020304
       value2=0x11121314
-      value3=0x21222324
+      value3=0xFFFEFDFC
       ;;
     double)
       value1=0x0102030405060708L
       value2=0x1112131415161718L
-      value3=0x2122232425262728L
+      value3=0xFFFEFDFCFBFAF9F8L
       ;;
   esac