8157152: Atomic add for VarHandle byte[]/ByteBuffer views is incorrect for endian conversion
Reviewed-by: fyuan, shade, vlivanov
--- 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