提交 ece51a42 编写于 作者: J jrose

7129034: VM crash with a field setter method with a filterArguments

Summary: add null checks before unsafe calls that take a variable base reference; update unit tests
Reviewed-by: kvn, twisti
上级 6afc9482
...@@ -190,32 +190,36 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -190,32 +190,36 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@Override @Override
String debugString() { return addTypeString(name, this); } String debugString() { return addTypeString(name, this); }
int getFieldI(Object /*C*/ obj) { return unsafe.getInt(obj, offset); } private static Object nullCheck(Object obj) {
void setFieldI(Object /*C*/ obj, int x) { unsafe.putInt(obj, offset, x); } obj.getClass(); // NPE
long getFieldJ(Object /*C*/ obj) { return unsafe.getLong(obj, offset); } return obj;
void setFieldJ(Object /*C*/ obj, long x) { unsafe.putLong(obj, offset, x); } }
float getFieldF(Object /*C*/ obj) { return unsafe.getFloat(obj, offset); }
void setFieldF(Object /*C*/ obj, float x) { unsafe.putFloat(obj, offset, x); } int getFieldI(Object /*C*/ obj) { return unsafe.getInt(nullCheck(obj), offset); }
double getFieldD(Object /*C*/ obj) { return unsafe.getDouble(obj, offset); } void setFieldI(Object /*C*/ obj, int x) { unsafe.putInt(nullCheck(obj), offset, x); }
void setFieldD(Object /*C*/ obj, double x) { unsafe.putDouble(obj, offset, x); } long getFieldJ(Object /*C*/ obj) { return unsafe.getLong(nullCheck(obj), offset); }
boolean getFieldZ(Object /*C*/ obj) { return unsafe.getBoolean(obj, offset); } void setFieldJ(Object /*C*/ obj, long x) { unsafe.putLong(nullCheck(obj), offset, x); }
void setFieldZ(Object /*C*/ obj, boolean x) { unsafe.putBoolean(obj, offset, x); } float getFieldF(Object /*C*/ obj) { return unsafe.getFloat(nullCheck(obj), offset); }
byte getFieldB(Object /*C*/ obj) { return unsafe.getByte(obj, offset); } void setFieldF(Object /*C*/ obj, float x) { unsafe.putFloat(nullCheck(obj), offset, x); }
void setFieldB(Object /*C*/ obj, byte x) { unsafe.putByte(obj, offset, x); } double getFieldD(Object /*C*/ obj) { return unsafe.getDouble(nullCheck(obj), offset); }
short getFieldS(Object /*C*/ obj) { return unsafe.getShort(obj, offset); } void setFieldD(Object /*C*/ obj, double x) { unsafe.putDouble(nullCheck(obj), offset, x); }
void setFieldS(Object /*C*/ obj, short x) { unsafe.putShort(obj, offset, x); } boolean getFieldZ(Object /*C*/ obj) { return unsafe.getBoolean(nullCheck(obj), offset); }
char getFieldC(Object /*C*/ obj) { return unsafe.getChar(obj, offset); } void setFieldZ(Object /*C*/ obj, boolean x) { unsafe.putBoolean(nullCheck(obj), offset, x); }
void setFieldC(Object /*C*/ obj, char x) { unsafe.putChar(obj, offset, x); } byte getFieldB(Object /*C*/ obj) { return unsafe.getByte(nullCheck(obj), offset); }
Object /*V*/ getFieldL(Object /*C*/ obj) { return unsafe.getObject(obj, offset); } void setFieldB(Object /*C*/ obj, byte x) { unsafe.putByte(nullCheck(obj), offset, x); }
void setFieldL(Object /*C*/ obj, Object /*V*/ x) { unsafe.putObject(obj, offset, x); } short getFieldS(Object /*C*/ obj) { return unsafe.getShort(nullCheck(obj), offset); }
// cast (V) is OK here, since we wrap convertArguments around the MH. void setFieldS(Object /*C*/ obj, short x) { unsafe.putShort(nullCheck(obj), offset, x); }
char getFieldC(Object /*C*/ obj) { return unsafe.getChar(nullCheck(obj), offset); }
void setFieldC(Object /*C*/ obj, char x) { unsafe.putChar(nullCheck(obj), offset, x); }
Object /*V*/ getFieldL(Object /*C*/ obj) { return unsafe.getObject(nullCheck(obj), offset); }
void setFieldL(Object /*C*/ obj, Object /*V*/ x) { unsafe.putObject(nullCheck(obj), offset, x); }
static Object staticBase(final MemberName field) { static Object staticBase(final MemberName field) {
if (!field.isStatic()) return null; if (!field.isStatic()) return null;
return AccessController.doPrivileged(new PrivilegedAction<Object>() { return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() { public Object run() {
try { try {
Class c = field.getDeclaringClass(); Class<?> c = field.getDeclaringClass();
// FIXME: Should not have to create 'f' to get this value. // FIXME: Should not have to create 'f' to get this value.
java.lang.reflect.Field f = c.getDeclaredField(field.getName()); java.lang.reflect.Field f = c.getDeclaredField(field.getName());
return unsafe.staticFieldBase(f); return unsafe.staticFieldBase(f);
...@@ -242,7 +246,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -242,7 +246,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
void setStaticS(short x) { unsafe.putShort(base, offset, x); } void setStaticS(short x) { unsafe.putShort(base, offset, x); }
char getStaticC() { return unsafe.getChar(base, offset); } char getStaticC() { return unsafe.getChar(base, offset); }
void setStaticC(char x) { unsafe.putChar(base, offset, x); } void setStaticC(char x) { unsafe.putChar(base, offset, x); }
@SuppressWarnings("unchecked") // (V) is for internal clarity but triggers warning
Object /*V*/ getStaticL() { return unsafe.getObject(base, offset); } Object /*V*/ getStaticL() { return unsafe.getObject(base, offset); }
void setStaticL(Object /*V*/ x) { unsafe.putObject(base, offset, x); } void setStaticL(Object /*V*/ x) { unsafe.putObject(base, offset, x); }
......
...@@ -280,6 +280,8 @@ public class MethodHandlesTest { ...@@ -280,6 +280,8 @@ public class MethodHandlesTest {
{ param = c; break; } { param = c; break; }
} }
} }
if (param.isInterface() && param.isAssignableFrom(List.class))
return Arrays.asList("#"+nextArg());
if (param.isInterface() || param.isAssignableFrom(String.class)) if (param.isInterface() || param.isAssignableFrom(String.class))
return "#"+nextArg(); return "#"+nextArg();
else else
...@@ -457,6 +459,7 @@ public class MethodHandlesTest { ...@@ -457,6 +459,7 @@ public class MethodHandlesTest {
@Override public String toString() { return name; } @Override public String toString() { return name; }
} }
} }
static interface SubIntExample extends IntExample { }
static final Object[][][] ACCESS_CASES = { static final Object[][][] ACCESS_CASES = {
{ { false, PUBLIC }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false { { false, PUBLIC }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false
...@@ -960,7 +963,7 @@ public class MethodHandlesTest { ...@@ -960,7 +963,7 @@ public class MethodHandlesTest {
} }
} }
static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10; static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10, TEST_NPE = 0x20;
static boolean testModeMatches(int testMode, boolean isStatic) { static boolean testModeMatches(int testMode, boolean isStatic) {
switch (testMode) { switch (testMode) {
case TEST_FIND_STATIC: return isStatic; case TEST_FIND_STATIC: return isStatic;
...@@ -990,6 +993,8 @@ public class MethodHandlesTest { ...@@ -990,6 +993,8 @@ public class MethodHandlesTest {
for (Object[] c : HasFields.CASES) { for (Object[] c : HasFields.CASES) {
boolean positive = (c[1] != Error.class); boolean positive = (c[1] != Error.class);
testGetter(positive, lookup, c[0], c[1], testMode); testGetter(positive, lookup, c[0], c[1], testMode);
if (positive)
testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
} }
testGetter(true, lookup, testGetter(true, lookup,
new Object[]{ true, System.class, "out", java.io.PrintStream.class }, new Object[]{ true, System.class, "out", java.io.PrintStream.class },
...@@ -1005,12 +1010,14 @@ public class MethodHandlesTest { ...@@ -1005,12 +1010,14 @@ public class MethodHandlesTest {
testAccessor(positive, lookup, fieldRef, value, testMode); testAccessor(positive, lookup, fieldRef, value, testMode);
} }
public void testAccessor(boolean positive, MethodHandles.Lookup lookup, public void testAccessor(boolean positive0, MethodHandles.Lookup lookup,
Object fieldRef, Object value, int testMode0) throws Throwable { Object fieldRef, Object value, int testMode0) throws Throwable {
if (verbosity >= 4) if (verbosity >= 4)
System.out.println("testAccessor"+Arrays.asList(positive, lookup, fieldRef, value, testMode0)); System.out.println("testAccessor"+Arrays.deepToString(new Object[]{positive0, lookup, fieldRef, value, testMode0}));
boolean isGetter = ((testMode0 & TEST_SETTER) == 0); boolean isGetter = ((testMode0 & TEST_SETTER) == 0);
int testMode = testMode0 & ~TEST_SETTER; boolean testNPE = ((testMode0 & TEST_NPE) != 0);
int testMode = testMode0 & ~(TEST_SETTER | TEST_NPE);
boolean positive = positive0 && !testNPE;
boolean isStatic; boolean isStatic;
Class<?> fclass; Class<?> fclass;
String fname; String fname;
...@@ -1035,6 +1042,7 @@ public class MethodHandlesTest { ...@@ -1035,6 +1042,7 @@ public class MethodHandlesTest {
} }
if (!testModeMatches(testMode, isStatic)) return; if (!testModeMatches(testMode, isStatic)) return;
if (f == null && testMode == TEST_UNREFLECT) return; if (f == null && testMode == TEST_UNREFLECT) return;
if (testNPE && isStatic) return;
countTest(positive); countTest(positive);
MethodType expType; MethodType expType;
if (isGetter) if (isGetter)
...@@ -1045,7 +1053,7 @@ public class MethodHandlesTest { ...@@ -1045,7 +1053,7 @@ public class MethodHandlesTest {
Exception noAccess = null; Exception noAccess = null;
MethodHandle mh; MethodHandle mh;
try { try {
switch (testMode0) { switch (testMode0 & ~TEST_NPE) {
case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break; case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break;
case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break; case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break;
case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break; case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break;
...@@ -1070,15 +1078,17 @@ public class MethodHandlesTest { ...@@ -1070,15 +1078,17 @@ public class MethodHandlesTest {
System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype
+" => "+mh +" => "+mh
+(noAccess == null ? "" : " !! "+noAccess)); +(noAccess == null ? "" : " !! "+noAccess));
if (positive && noAccess != null) throw new RuntimeException(noAccess); if (positive && !testNPE && noAccess != null) throw new RuntimeException(noAccess);
assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, mh != null); assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null);
if (!positive) return; // negative test failed as expected if (!positive && !testNPE) return; // negative access test failed as expected
assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount()); assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount());
assertSame(mh.type(), expType); assertSame(mh.type(), expType);
assertNameStringContains(mh, fname); assertNameStringContains(mh, fname);
HasFields fields = new HasFields(); HasFields fields = new HasFields();
HasFields fieldsForMH = fields;
if (testNPE) fieldsForMH = null; // perturb MH argument to elicit expected error
Object sawValue; Object sawValue;
Class<?> vtype = ftype; Class<?> vtype = ftype;
if (ftype != int.class) vtype = Object.class; if (ftype != int.class) vtype = Object.class;
...@@ -1094,6 +1104,7 @@ public class MethodHandlesTest { ...@@ -1094,6 +1104,7 @@ public class MethodHandlesTest {
if (f != null && f.getDeclaringClass() == HasFields.class) { if (f != null && f.getDeclaringClass() == HasFields.class) {
assertEquals(f.get(fields), value); // clean to start with assertEquals(f.get(fields), value); // clean to start with
} }
Throwable caughtEx = null;
if (isGetter) { if (isGetter) {
Object expValue = value; Object expValue = value;
for (int i = 0; i <= 1; i++) { for (int i = 0; i <= 1; i++) {
...@@ -1103,10 +1114,18 @@ public class MethodHandlesTest { ...@@ -1103,10 +1114,18 @@ public class MethodHandlesTest {
else else
sawValue = mh.invokeExact(); sawValue = mh.invokeExact();
} else { } else {
if (ftype == int.class) sawValue = null; // make DA rules happy under try/catch
sawValue = (int) mh.invokeExact((Object) fields); try {
else if (ftype == int.class)
sawValue = mh.invokeExact((Object) fields); sawValue = (int) mh.invokeExact((Object) fieldsForMH);
else
sawValue = mh.invokeExact((Object) fieldsForMH);
} catch (RuntimeException ex) {
if (ex instanceof NullPointerException && testNPE) {
caughtEx = ex;
break;
}
}
} }
assertEquals(sawValue, expValue); assertEquals(sawValue, expValue);
if (f != null && f.getDeclaringClass() == HasFields.class if (f != null && f.getDeclaringClass() == HasFields.class
...@@ -1127,10 +1146,17 @@ public class MethodHandlesTest { ...@@ -1127,10 +1146,17 @@ public class MethodHandlesTest {
else else
mh.invokeExact(putValue); mh.invokeExact(putValue);
} else { } else {
if (ftype == int.class) try {
mh.invokeExact((Object) fields, (int)putValue); if (ftype == int.class)
else mh.invokeExact((Object) fieldsForMH, (int)putValue);
mh.invokeExact((Object) fields, putValue); else
mh.invokeExact((Object) fieldsForMH, putValue);
} catch (RuntimeException ex) {
if (ex instanceof NullPointerException && testNPE) {
caughtEx = ex;
break;
}
}
} }
if (f != null && f.getDeclaringClass() == HasFields.class) { if (f != null && f.getDeclaringClass() == HasFields.class) {
assertEquals(f.get(fields), putValue); assertEquals(f.get(fields), putValue);
...@@ -1140,6 +1166,14 @@ public class MethodHandlesTest { ...@@ -1140,6 +1166,14 @@ public class MethodHandlesTest {
if (f != null && f.getDeclaringClass() == HasFields.class) { if (f != null && f.getDeclaringClass() == HasFields.class) {
f.set(fields, value); // put it back f.set(fields, value); // put it back
} }
if (testNPE) {
if (caughtEx == null || !(caughtEx instanceof NullPointerException))
throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx);
caughtEx = null; // nullify expected exception
}
if (caughtEx != null) {
throw new RuntimeException("unexpected exception", caughtEx);
}
} }
...@@ -1164,6 +1198,8 @@ public class MethodHandlesTest { ...@@ -1164,6 +1198,8 @@ public class MethodHandlesTest {
for (Object[] c : HasFields.CASES) { for (Object[] c : HasFields.CASES) {
boolean positive = (c[1] != Error.class); boolean positive = (c[1] != Error.class);
testSetter(positive, lookup, c[0], c[1], testMode); testSetter(positive, lookup, c[0], c[1], testMode);
if (positive)
testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
} }
for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {
testSetter(false, lookup, testSetter(false, lookup,
...@@ -1188,24 +1224,71 @@ public class MethodHandlesTest { ...@@ -1188,24 +1224,71 @@ public class MethodHandlesTest {
testArrayElementGetterSetter(true); testArrayElementGetterSetter(true);
} }
private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3;
public void testArrayElementGetterSetter(boolean testSetter) throws Throwable { public void testArrayElementGetterSetter(boolean testSetter) throws Throwable {
testArrayElementGetterSetter(new Object[10], testSetter); testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE);
testArrayElementGetterSetter(new String[10], testSetter); }
testArrayElementGetterSetter(new boolean[10], testSetter);
testArrayElementGetterSetter(new byte[10], testSetter); @Test
testArrayElementGetterSetter(new char[10], testSetter); public void testArrayElementErrors() throws Throwable {
testArrayElementGetterSetter(new short[10], testSetter); startTest("arrayElementErrors");
testArrayElementGetterSetter(new int[10], testSetter); testArrayElementGetterSetter(false, TEST_ARRAY_NPE);
testArrayElementGetterSetter(new float[10], testSetter); testArrayElementGetterSetter(true, TEST_ARRAY_NPE);
testArrayElementGetterSetter(new long[10], testSetter); testArrayElementGetterSetter(false, TEST_ARRAY_OOB);
testArrayElementGetterSetter(new double[10], testSetter); testArrayElementGetterSetter(true, TEST_ARRAY_OOB);
} testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE);
testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE);
public void testArrayElementGetterSetter(Object array, boolean testSetter) throws Throwable { testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE);
countTest(true); }
if (verbosity > 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+Array.getLength(array)+"]");
public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable {
testArrayElementGetterSetter(new String[10], testSetter, negTest);
testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest);
testArrayElementGetterSetter(new Example[10], testSetter, negTest);
testArrayElementGetterSetter(new IntExample[10], testSetter, negTest);
testArrayElementGetterSetter(new Object[10], testSetter, negTest);
testArrayElementGetterSetter(new boolean[10], testSetter, negTest);
testArrayElementGetterSetter(new byte[10], testSetter, negTest);
testArrayElementGetterSetter(new char[10], testSetter, negTest);
testArrayElementGetterSetter(new short[10], testSetter, negTest);
testArrayElementGetterSetter(new int[10], testSetter, negTest);
testArrayElementGetterSetter(new float[10], testSetter, negTest);
testArrayElementGetterSetter(new long[10], testSetter, negTest);
testArrayElementGetterSetter(new double[10], testSetter, negTest);
}
public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable {
boolean positive = (negTest == TEST_ARRAY_NONE);
int length = java.lang.reflect.Array.getLength(array);
Class<?> arrayType = array.getClass(); Class<?> arrayType = array.getClass();
Class<?> elemType = arrayType.getComponentType(); Class<?> elemType = arrayType.getComponentType();
Object arrayToMH = array;
// this stanza allows negative tests to make argument perturbations:
switch (negTest) {
case TEST_ARRAY_NPE:
arrayToMH = null;
break;
case TEST_ARRAY_OOB:
assert(length > 0);
arrayToMH = java.lang.reflect.Array.newInstance(elemType, 0);
break;
case TEST_ARRAY_ASE:
assert(testSetter && !elemType.isPrimitive());
if (elemType == Object.class)
arrayToMH = new StringBuffer[length]; // very random subclass of Object!
else if (elemType == Example.class)
arrayToMH = new SubExample[length];
else if (elemType == IntExample.class)
arrayToMH = new SubIntExample[length];
else
return; // can't make an ArrayStoreException test
assert(arrayType.isInstance(arrayToMH))
: Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest);
break;
}
countTest(positive);
if (verbosity > 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+length+"]"+(positive ? "" : " negative test #"+negTest+" using "+Arrays.deepToString(new Object[]{arrayToMH})));
MethodType expType = !testSetter MethodType expType = !testSetter
? MethodType.methodType(elemType, arrayType, int.class) ? MethodType.methodType(elemType, arrayType, int.class)
: MethodType.methodType(void.class, arrayType, int.class, elemType); : MethodType.methodType(void.class, arrayType, int.class, elemType);
...@@ -1214,25 +1297,29 @@ public class MethodHandlesTest { ...@@ -1214,25 +1297,29 @@ public class MethodHandlesTest {
: MethodHandles.arrayElementSetter(arrayType); : MethodHandles.arrayElementSetter(arrayType);
assertSame(mh.type(), expType); assertSame(mh.type(), expType);
if (elemType != int.class && elemType != boolean.class) { if (elemType != int.class && elemType != boolean.class) {
// FIXME: change Integer.class and (Integer) below to int.class and (int) below. MethodType gtype = mh.type().generic().changeParameterType(1, int.class);
MethodType gtype = mh.type().generic().changeParameterType(1, Integer.class);
if (testSetter) gtype = gtype.changeReturnType(void.class); if (testSetter) gtype = gtype.changeReturnType(void.class);
mh = mh.asType(gtype); mh = mh.asType(gtype);
} }
Object sawValue, expValue; Object sawValue, expValue;
List<Object> model = array2list(array); List<Object> model = array2list(array);
int length = Array.getLength(array); Throwable caughtEx = null;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
// update array element // update array element
Object random = randomArg(elemType); Object random = randomArg(elemType);
model.set(i, random); model.set(i, random);
if (testSetter) { if (testSetter) {
if (elemType == int.class) try {
mh.invokeExact((int[]) array, i, (int)random); if (elemType == int.class)
else if (elemType == boolean.class) mh.invokeExact((int[]) arrayToMH, i, (int)random);
mh.invokeExact((boolean[]) array, i, (boolean)random); else if (elemType == boolean.class)
else mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random);
mh.invokeExact(array, (Integer)i, random); else
mh.invokeExact(arrayToMH, i, random);
} catch (RuntimeException ex) {
caughtEx = ex;
break;
}
assertEquals(model, array2list(array)); assertEquals(model, array2list(array));
} else { } else {
Array.set(array, i, random); Array.set(array, i, random);
...@@ -1247,16 +1334,39 @@ public class MethodHandlesTest { ...@@ -1247,16 +1334,39 @@ public class MethodHandlesTest {
sawValue = Array.get(array, i); sawValue = Array.get(array, i);
if (!testSetter) { if (!testSetter) {
expValue = sawValue; expValue = sawValue;
if (elemType == int.class) try {
sawValue = (int) mh.invokeExact((int[]) array, i); if (elemType == int.class)
else if (elemType == boolean.class) sawValue = (int) mh.invokeExact((int[]) arrayToMH, i);
sawValue = (boolean) mh.invokeExact((boolean[]) array, i); else if (elemType == boolean.class)
else sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i);
sawValue = mh.invokeExact(array, (Integer)i); else
sawValue = mh.invokeExact(arrayToMH, i);
} catch (RuntimeException ex) {
caughtEx = ex;
break;
}
assertEquals(sawValue, expValue); assertEquals(sawValue, expValue);
assertEquals(model, array2list(array)); assertEquals(model, array2list(array));
} }
} }
if (!positive) {
if (caughtEx == null)
throw new RuntimeException("failed to catch exception for negTest="+negTest);
// test the kind of exception
Class<?> reqType = null;
switch (negTest) {
case TEST_ARRAY_ASE: reqType = ArrayStoreException.class; break;
case TEST_ARRAY_OOB: reqType = ArrayIndexOutOfBoundsException.class; break;
case TEST_ARRAY_NPE: reqType = NullPointerException.class; break;
default: assert(false);
}
if (reqType.isInstance(caughtEx)) {
caughtEx = null; // nullify expected exception
}
}
if (caughtEx != null) {
throw new RuntimeException("unexpected exception", caughtEx);
}
} }
List<Object> array2list(Object array) { List<Object> array2list(Object array) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册