8194233: Improve support for array handles

Reviewed-by: jrose, vlivanov, ahgross, rhalade
This commit is contained in:
Paul Sandoz 2018-01-22 13:27:28 -08:00
parent 97c8fdb2dd
commit 9b54e6d766
12 changed files with 248 additions and 24 deletions

View File

@ -592,6 +592,28 @@ final class VarHandle$Type$s {
return accessMode.at.accessModeType({#if[Object]?arrayType:$type$[].class}, {#if[Object]?arrayType.getComponentType():$type$.class}, int.class);
}
#if[Object]
@ForceInline
static Object runtimeTypeCheck(Array handle, Object[] oarray, Object value) {
if (handle.arrayType == oarray.getClass()) {
// Fast path: static array type same as argument array type
return handle.componentType.cast(value);
} else {
// Slow path: check value against argument array component type
return reflectiveTypeCheck(oarray, value);
}
}
@ForceInline
static Object reflectiveTypeCheck(Object[] oarray, Object value) {
try {
return oarray.getClass().getComponentType().cast(value);
} catch (ClassCastException e) {
throw new ArrayStoreException();
}
}
#end[Object]
@ForceInline
static $type$ get(Array handle, Object oarray, int index) {
#if[Object]
@ -632,7 +654,7 @@ final class VarHandle$Type$s {
#end[Object]
UNSAFE.put$Type$Volatile(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -655,7 +677,7 @@ final class VarHandle$Type$s {
#end[Object]
UNSAFE.put$Type$Opaque(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -678,7 +700,7 @@ final class VarHandle$Type$s {
#end[Object]
UNSAFE.put$Type$Release(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
#if[CAS]
@ -692,7 +714,7 @@ final class VarHandle$Type$s {
return UNSAFE.compareAndSet$Type$(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -705,7 +727,7 @@ final class VarHandle$Type$s {
return UNSAFE.compareAndExchange$Type$(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -718,7 +740,7 @@ final class VarHandle$Type$s {
return UNSAFE.compareAndExchange$Type$Acquire(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -731,7 +753,7 @@ final class VarHandle$Type$s {
return UNSAFE.compareAndExchange$Type$Release(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -744,7 +766,7 @@ final class VarHandle$Type$s {
return UNSAFE.weakCompareAndSet$Type$Plain(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -757,7 +779,7 @@ final class VarHandle$Type$s {
return UNSAFE.weakCompareAndSet$Type$(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -770,7 +792,7 @@ final class VarHandle$Type$s {
return UNSAFE.weakCompareAndSet$Type$Acquire(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -783,7 +805,7 @@ final class VarHandle$Type$s {
return UNSAFE.weakCompareAndSet$Type$Release(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -795,7 +817,7 @@ final class VarHandle$Type$s {
#end[Object]
return UNSAFE.getAndSet$Type$(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -807,7 +829,7 @@ final class VarHandle$Type$s {
#end[Object]
return UNSAFE.getAndSet$Type$Acquire(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@ -819,7 +841,7 @@ final class VarHandle$Type$s {
#end[Object]
return UNSAFE.getAndSet$Type$Release(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(value):value});
{#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
#end[CAS]
#if[AtomicAdd]

View File

@ -70,6 +70,14 @@ abstract class VarHandleBaseTest {
checkWithThrowable(IndexOutOfBoundsException.class, message, r);
}
static void checkASE(ThrowingRunnable r) {
checkWithThrowable(ArrayStoreException.class, null, r);
}
static void checkASE(Object message, ThrowingRunnable r) {
checkWithThrowable(ArrayStoreException.class, message, r);
}
static void checkISE(ThrowingRunnable r) {
checkWithThrowable(IllegalStateException.class, null, r);
}

View File

@ -60,6 +60,7 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest {
VarHandle vhArray;
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -210,7 +211,6 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccessBoolean::testArrayIndexOutOfBounds,
false));
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1255,5 +1255,6 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest {
});
}
}
}

View File

@ -60,6 +60,7 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest {
VarHandle vhArray;
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -210,7 +211,6 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccessByte::testArrayIndexOutOfBounds,
false));
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1292,5 +1292,6 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest {
});
}
}
}

View File

@ -60,6 +60,7 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest {
VarHandle vhArray;
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -210,7 +211,6 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccessChar::testArrayIndexOutOfBounds,
false));
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1292,5 +1292,6 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest {
});
}
}
}

View File

@ -60,6 +60,7 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest {
VarHandle vhArray;
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -210,7 +211,6 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccessDouble::testArrayIndexOutOfBounds,
false));
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1183,5 +1183,6 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest {
}
}
}

View File

@ -60,6 +60,7 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest {
VarHandle vhArray;
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -210,7 +211,6 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccessFloat::testArrayIndexOutOfBounds,
false));
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1183,5 +1183,6 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest {
}
}
}

View File

@ -60,6 +60,7 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest {
VarHandle vhArray;
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -210,7 +211,6 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccessInt::testArrayIndexOutOfBounds,
false));
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1292,5 +1292,6 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest {
});
}
}
}

View File

@ -60,6 +60,7 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest {
VarHandle vhArray;
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -210,7 +211,6 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccessLong::testArrayIndexOutOfBounds,
false));
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1292,5 +1292,6 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest {
});
}
}
}

View File

@ -60,6 +60,7 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest {
VarHandle vhArray;
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -210,7 +211,6 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccessShort::testArrayIndexOutOfBounds,
false));
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1292,5 +1292,6 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest {
});
}
}
}

View File

@ -60,6 +60,8 @@ public class VarHandleTestAccessString extends VarHandleBaseTest {
VarHandle vhArray;
VarHandle vhArrayObject;
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -75,6 +77,7 @@ public class VarHandleTestAccessString extends VarHandleBaseTest {
VarHandleTestAccessString.class, "static_v", String.class);
vhArray = MethodHandles.arrayElementVarHandle(String[].class);
vhArrayObject = MethodHandles.arrayElementVarHandle(Object[].class);
}
@ -204,13 +207,17 @@ public class VarHandleTestAccessString extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array",
vhArray, VarHandleTestAccessString::testArray));
cases.add(new VarHandleAccessTestCase("Array Object[]",
vhArrayObject, VarHandleTestAccessString::testArray));
cases.add(new VarHandleAccessTestCase("Array unsupported",
vhArray, VarHandleTestAccessString::testArrayUnsupported,
false));
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccessString::testArrayIndexOutOfBounds,
false));
cases.add(new VarHandleAccessTestCase("Array store exception",
vhArrayObject, VarHandleTestAccessString::testArrayStoreException,
false));
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1146,5 +1153,86 @@ public class VarHandleTestAccessString extends VarHandleBaseTest {
}
}
static void testArrayStoreException(VarHandle vh) throws Throwable {
Object[] array = new String[10];
Arrays.fill(array, "foo");
Object value = new Object();
// Set
checkASE(() -> {
vh.set(array, 0, value);
});
// SetVolatile
checkASE(() -> {
vh.setVolatile(array, 0, value);
});
// SetOpaque
checkASE(() -> {
vh.setOpaque(array, 0, value);
});
// SetRelease
checkASE(() -> {
vh.setRelease(array, 0, value);
});
// CompareAndSet
checkASE(() -> { // receiver reference class
boolean r = vh.compareAndSet(array, 0, "foo", value);
});
// WeakCompareAndSet
checkASE(() -> { // receiver reference class
boolean r = vh.weakCompareAndSetPlain(array, 0, "foo", value);
});
// WeakCompareAndSetVolatile
checkASE(() -> { // receiver reference class
boolean r = vh.weakCompareAndSet(array, 0, "foo", value);
});
// WeakCompareAndSetAcquire
checkASE(() -> { // receiver reference class
boolean r = vh.weakCompareAndSetAcquire(array, 0, "foo", value);
});
// WeakCompareAndSetRelease
checkASE(() -> { // receiver reference class
boolean r = vh.weakCompareAndSetRelease(array, 0, "foo", value);
});
// CompareAndExchange
checkASE(() -> { // receiver reference class
String x = (String) vh.compareAndExchange(array, 0, "foo", value);
});
// CompareAndExchangeAcquire
checkASE(() -> { // receiver reference class
String x = (String) vh.compareAndExchangeAcquire(array, 0, "foo", value);
});
// CompareAndExchangeRelease
checkASE(() -> { // receiver reference class
String x = (String) vh.compareAndExchangeRelease(array, 0, "foo", value);
});
// GetAndSet
checkASE(() -> { // receiver reference class
String x = (String) vh.getAndSet(array, 0, value);
});
// GetAndSetAcquire
checkASE(() -> { // receiver reference class
String x = (String) vh.getAndSetAcquire(array, 0, value);
});
// GetAndSetRelease
checkASE(() -> { // receiver reference class
String x = (String) vh.getAndSetRelease(array, 0, value);
});
}
}

View File

@ -60,6 +60,10 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest {
VarHandle vhArray;
#if[String]
VarHandle vhArrayObject;
#end[String]
@BeforeClass
public void setup() throws Exception {
vhFinalField = MethodHandles.lookup().findVarHandle(
@ -75,6 +79,9 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest {
VarHandleTestAccess$Type$.class, "static_v", $type$.class);
vhArray = MethodHandles.arrayElementVarHandle($type$[].class);
#if[String]
vhArrayObject = MethodHandles.arrayElementVarHandle(Object[].class);
#end[String]
}
@ -236,13 +243,21 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest {
cases.add(new VarHandleAccessTestCase("Array",
vhArray, VarHandleTestAccess$Type$::testArray));
#if[String]
cases.add(new VarHandleAccessTestCase("Array Object[]",
vhArrayObject, VarHandleTestAccess$Type$::testArray));
#end[String]
cases.add(new VarHandleAccessTestCase("Array unsupported",
vhArray, VarHandleTestAccess$Type$::testArrayUnsupported,
false));
cases.add(new VarHandleAccessTestCase("Array index out of bounds",
vhArray, VarHandleTestAccess$Type$::testArrayIndexOutOfBounds,
false));
#if[String]
cases.add(new VarHandleAccessTestCase("Array store exception",
vhArrayObject, VarHandleTestAccess$Type$::testArrayStoreException,
false));
#end[String]
// Work around issue with jtreg summary reporting which truncates
// the String result of Object.toString to 30 characters, hence
// the first dummy argument
@ -1823,5 +1838,88 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest {
#end[Bitwise]
}
}
#if[String]
static void testArrayStoreException(VarHandle vh) throws Throwable {
Object[] array = new $type$[10];
Arrays.fill(array, $value1$);
Object value = new Object();
// Set
checkASE(() -> {
vh.set(array, 0, value);
});
// SetVolatile
checkASE(() -> {
vh.setVolatile(array, 0, value);
});
// SetOpaque
checkASE(() -> {
vh.setOpaque(array, 0, value);
});
// SetRelease
checkASE(() -> {
vh.setRelease(array, 0, value);
});
// CompareAndSet
checkASE(() -> { // receiver reference class
boolean r = vh.compareAndSet(array, 0, $value1$, value);
});
// WeakCompareAndSet
checkASE(() -> { // receiver reference class
boolean r = vh.weakCompareAndSetPlain(array, 0, $value1$, value);
});
// WeakCompareAndSetVolatile
checkASE(() -> { // receiver reference class
boolean r = vh.weakCompareAndSet(array, 0, $value1$, value);
});
// WeakCompareAndSetAcquire
checkASE(() -> { // receiver reference class
boolean r = vh.weakCompareAndSetAcquire(array, 0, $value1$, value);
});
// WeakCompareAndSetRelease
checkASE(() -> { // receiver reference class
boolean r = vh.weakCompareAndSetRelease(array, 0, $value1$, value);
});
// CompareAndExchange
checkASE(() -> { // receiver reference class
$type$ x = ($type$) vh.compareAndExchange(array, 0, $value1$, value);
});
// CompareAndExchangeAcquire
checkASE(() -> { // receiver reference class
$type$ x = ($type$) vh.compareAndExchangeAcquire(array, 0, $value1$, value);
});
// CompareAndExchangeRelease
checkASE(() -> { // receiver reference class
$type$ x = ($type$) vh.compareAndExchangeRelease(array, 0, $value1$, value);
});
// GetAndSet
checkASE(() -> { // receiver reference class
$type$ x = ($type$) vh.getAndSet(array, 0, value);
});
// GetAndSetAcquire
checkASE(() -> { // receiver reference class
$type$ x = ($type$) vh.getAndSetAcquire(array, 0, value);
});
// GetAndSetRelease
checkASE(() -> { // receiver reference class
$type$ x = ($type$) vh.getAndSetRelease(array, 0, value);
});
}
#end[String]
}