提交 8cd530d6 编写于 作者: J jrose

7058651: JSR 292 unit tests need a refresh

Summary: Enhancements to unit tests.
Reviewed-by: never, twisti
上级 0059e8b2
......@@ -69,6 +69,7 @@ public class JavaDocExamplesTest {
testDropArguments();
testFilterArguments();
testFoldArguments();
testFoldArguments2();
testMethodHandlesSummary();
testAsSpreader();
testAsCollector();
......@@ -490,6 +491,47 @@ assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
}}
}
@Test public void testFoldArguments2() throws Throwable {
{{
{} /// JAVADOC
// argument-based dispatch for methods of the form boolean x.___(y: String)
Lookup lookup = publicLookup();
// first, a tracing hack:
MethodHandle println = lookup.findVirtual(java.io.PrintStream.class, "println", methodType(void.class, String.class));
MethodHandle arrayToString = lookup.findStatic(Arrays.class, "toString", methodType(String.class, Object[].class));
MethodHandle concat = lookup.findVirtual(String.class, "concat", methodType(String.class, String.class));
MethodHandle arrayToString_DIS = filterReturnValue(arrayToString, concat.bindTo("DIS:"));
MethodHandle arrayToString_INV = filterReturnValue(arrayToString, concat.bindTo("INV:"));
MethodHandle printArgs_DIS = filterReturnValue(arrayToString_DIS, println.bindTo(System.out)).asVarargsCollector(Object[].class);
MethodHandle printArgs_INV = filterReturnValue(arrayToString_INV, println.bindTo(System.out)).asVarargsCollector(Object[].class);
// metaobject protocol:
MethodType mtype = methodType(boolean.class, String.class);
MethodHandle findVirtual = lookup.findVirtual(Lookup.class,
"findVirtual", methodType(MethodHandle.class, Class.class, String.class, MethodType.class));
MethodHandle getClass = lookup.findVirtual(Object.class,
"getClass", methodType(Class.class));
MethodHandle dispatch = findVirtual;
dispatch = filterArguments(dispatch, 1, getClass);
dispatch = insertArguments(dispatch, 3, mtype);
dispatch = dispatch.bindTo(lookup);
assertEquals(methodType(MethodHandle.class, Object.class, String.class), dispatch.type());
MethodHandle invoker = invoker(mtype.insertParameterTypes(0, Object.class));
// wrap tracing around the dispatch and invoke steps:
dispatch = foldArguments(dispatch, printArgs_DIS.asType(dispatch.type().changeReturnType(void.class)));
invoker = foldArguments(invoker, printArgs_INV.asType(invoker.type().changeReturnType(void.class)));
invoker = dropArguments(invoker, 2, String.class); // ignore selector
// compose the dispatcher and the invoker:
MethodHandle invokeDispatched = foldArguments(invoker, dispatch);
Object x = "football", y = new java.util.Scanner("bar");
assert( (boolean) invokeDispatched.invokeExact(x, "startsWith", "foo"));
assert(!(boolean) invokeDispatched.invokeExact(x, "startsWith", "#"));
assert( (boolean) invokeDispatched.invokeExact(x, "endsWith", "all"));
assert(!(boolean) invokeDispatched.invokeExact(x, "endsWith", "foo"));
assert( (boolean) invokeDispatched.invokeExact(y, "hasNext", "[abc]+[rst]"));
assert(!(boolean) invokeDispatched.invokeExact(y, "hasNext", "[123]+[789]"));
}}
}
/* ---- TEMPLATE ----
@Test public void testFoo() throws Throwable {
{{
......
......@@ -37,7 +37,6 @@ import java.lang.reflect.*;
import java.util.*;
import org.junit.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
/**
......@@ -45,10 +44,13 @@ import static org.junit.Assume.*;
* @author jrose
*/
public class MethodHandlesTest {
static final Class<?> THIS_CLASS = MethodHandlesTest.class;
// How much output?
static int verbosity = 0;
static {
String vstr = System.getProperty("test.java.lang.invoke.MethodHandlesTest.verbosity");
String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");
if (vstr == null)
vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");
if (vstr != null) verbosity = Integer.parseInt(vstr);
}
......@@ -58,9 +60,9 @@ public class MethodHandlesTest {
static boolean CAN_SKIP_WORKING = false;
//static { CAN_SKIP_WORKING = true; }
// Set true to test more calls. If false, some tests are just
// lookups, without exercising the actual method handle.
static boolean DO_MORE_CALLS = true;
// Set 'true' to do about 15x fewer tests, especially those redundant with RicochetTest.
// This might be useful with -Xcomp stress tests that compile all method handles.
static boolean CAN_TEST_LIGHTLY = Boolean.getBoolean(THIS_CLASS.getName()+".CAN_TEST_LIGHTLY");
@Test
public void testFirst() throws Throwable {
......@@ -70,37 +72,37 @@ public class MethodHandlesTest {
}
// current failures
@Test @Ignore("failure in call to makeRawRetypeOnly in ToGeneric")
@Test //@Ignore("failure in call to makeRawRetypeOnly in ToGeneric")
public void testFail_1() throws Throwable {
// AMH.<init>: IllegalArgumentException: bad adapter (conversion=0xfffab300): adapter pushes too many parameters
testSpreadArguments(int.class, 0, 6);
}
@Test @Ignore("failure in JVM when expanding the stack using asm stub for _adapter_spread_args")
@Test //@Ignore("failure in JVM when expanding the stack using asm stub for _adapter_spread_args")
public void testFail_2() throws Throwable {
// if CONV_OP_IMPLEMENTED_MASK includes OP_SPREAD_ARGS, this crashes:
testSpreadArguments(Object.class, 0, 2);
}
@Test @Ignore("IllArgEx failure in call to ToGeneric.make")
@Test //@Ignore("IllArgEx failure in call to ToGeneric.make")
public void testFail_3() throws Throwable {
// ToGeneric.<init>: UnsupportedOperationException: NYI: primitive parameters must follow references; entryType = (int,java.lang.Object)java.lang.Object
testSpreadArguments(int.class, 1, 2);
}
@Test @Ignore("IllArgEx failure in call to ToGeneric.make")
@Test //@Ignore("IllArgEx failure in call to ToGeneric.make")
public void testFail_4() throws Throwable {
// ToGeneric.<init>: UnsupportedOperationException: NYI: primitive parameters must follow references; entryType = (int,java.lang.Object)java.lang.Object
testCollectArguments(int.class, 1, 2);
}
@Test @Ignore("cannot collect leading primitive types")
@Test //@Ignore("cannot collect leading primitive types")
public void testFail_5() throws Throwable {
// ToGeneric.<init>: UnsupportedOperationException: NYI: primitive parameters must follow references; entryType = (int,java.lang.Object)java.lang.Object
testInvokers(MethodType.genericMethodType(2).changeParameterType(0, int.class));
}
@Test @Ignore("should not insert arguments beyond MethodHandlePushLimit")
@Test //@Ignore("should not insert arguments beyond MethodHandlePushLimit")
public void testFail_6() throws Throwable {
// ValueConversions.varargsArray: UnsupportedOperationException: NYI: cannot form a varargs array of length 13
testInsertArguments(0, 0, MAX_ARG_INCREASE+10);
}
@Test @Ignore("permuteArguments has trouble with double slots")
@Test //@Ignore("permuteArguments has trouble with double slots")
public void testFail_7() throws Throwable {
testPermuteArguments(new Object[]{10, 200L},
new Class<?>[]{Integer.class, long.class},
......@@ -123,7 +125,7 @@ public class MethodHandlesTest {
testPermuteArguments(new Object[]{10, 200L, 5000L},
new Class<?>[]{Integer.class, long.class, long.class},
new int[]{2,2,0,1});
testPermuteArguments(4, Integer.class, 2, long.class, 6);
//testPermuteArguments(4, Integer.class, 2, long.class, 6);
}
static final int MAX_ARG_INCREASE = 3;
......@@ -167,7 +169,7 @@ public class MethodHandlesTest {
@AfterClass
public static void tearDownClass() throws Exception {
int posTests = allPosTests, negTests = allNegTests;
if (verbosity >= 2 && (posTests | negTests) != 0) {
if (verbosity >= 0 && (posTests | negTests) != 0) {
System.out.println();
if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases");
if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases");
......@@ -383,6 +385,13 @@ public class MethodHandlesTest {
MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
return target.asType(ttype2);
}
static MethodHandle addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass) {
int targetLen = target.type().parameterCount();
int extra = (nargs - targetLen);
if (extra <= 0) return target;
List<Class<?>> fakeArgs = Collections.<Class<?>>nCopies(extra, argClass);
return MethodHandles.dropArguments(target, targetLen, fakeArgs);
}
// This lookup is good for all members in and under MethodHandlesTest.
static final Lookup PRIVATE = MethodHandles.lookup();
......@@ -419,6 +428,10 @@ public class MethodHandlesTest {
public static Object s6(int x, long y) { return called("s6", x, y); }
public static Object s7(float x, double y) { return called("s7", x, y); }
// for testing findConstructor:
public Example(String x, int y) { this.name = x+y; called("Example.<init>", x, y); }
public Example(int x, String y) { this.name = x+y; called("Example.<init>", x, y); }
static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial
}
static final Lookup EXAMPLE = Example.EXAMPLE;
......@@ -521,7 +534,6 @@ public class MethodHandlesTest {
if (!positive) return; // negative test failed as expected
assertEquals(type, target.type());
assertNameStringContains(target, name);
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
Object[] args = randomArgs(params);
printCalled(target, name, args);
target.invokeWithArguments(args);
......@@ -604,7 +616,6 @@ public class MethodHandlesTest {
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
assertEquals(typeWithSelf, target.type());
assertNameStringContains(target, methodName);
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
Object[] argsWithSelf = randomArgs(paramsWithSelf);
if (rcvc != defc) argsWithSelf[0] = randomArg(rcvc);
printCalled(target, name, argsWithSelf);
......@@ -666,13 +677,49 @@ public class MethodHandlesTest {
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params);
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
assertNameStringContains(target, name);
if (!DO_MORE_CALLS && lookup != PRIVATE && lookup != EXAMPLE) return;
Object[] args = randomArgs(paramsWithSelf);
printCalled(target, name, args);
target.invokeWithArguments(args);
assertCalled(name, args);
}
@Test
public void testFindConstructor() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("findConstructor");
testFindConstructor(true, EXAMPLE, Example.class);
testFindConstructor(true, EXAMPLE, Example.class, int.class);
testFindConstructor(true, EXAMPLE, Example.class, String.class);
}
void testFindConstructor(boolean positive, Lookup lookup,
Class<?> defc, Class<?>... params) throws Throwable {
countTest(positive);
MethodType type = MethodType.methodType(void.class, params);
MethodHandle target = null;
Exception noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" <init>"+type);
target = lookup.findConstructor(defc, type);
} catch (ReflectiveOperationException ex) {
noAccess = ex;
assertTrue(noAccess instanceof IllegalAccessException);
}
if (verbosity >= 3)
System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target
+(target == null ? "" : target.type())
+(noAccess == null ? "" : " !! "+noAccess));
if (positive && noAccess != null) throw noAccess;
assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
if (!positive) return; // negative test failed as expected
assertEquals(type.changeReturnType(defc), target.type());
Object[] args = randomArgs(params);
printCalled(target, defc.getSimpleName(), args);
Object obj = target.invokeWithArguments(args);
if (!(defc == Example.class && params.length < 2))
assertCalled(defc.getSimpleName()+".<init>", args);
assertTrue("instance of "+defc.getName(), defc.isInstance(obj));
}
@Test
public void testBind() throws Throwable {
if (CAN_SKIP_WORKING) return;
......@@ -956,6 +1003,8 @@ public class MethodHandlesTest {
public void testAccessor(boolean positive, MethodHandles.Lookup lookup,
Object fieldRef, Object value, int testMode0) throws Throwable {
if (verbosity >= 4)
System.out.println("testAccessor"+Arrays.asList(positive, lookup, fieldRef, value, testMode0));
boolean isGetter = ((testMode0 & TEST_SETTER) == 0);
int testMode = testMode0 & ~TEST_SETTER;
boolean isStatic;
......@@ -1150,7 +1199,7 @@ public class MethodHandlesTest {
public void testArrayElementGetterSetter(Object array, boolean testSetter) throws Throwable {
countTest(true);
if (verbosity >= 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+Array.getLength(array)+"]");
if (verbosity > 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+Array.getLength(array)+"]");
Class<?> arrayType = array.getClass();
Class<?> elemType = arrayType.getComponentType();
MethodType expType = !testSetter
......@@ -1326,9 +1375,10 @@ public class MethodHandlesTest {
public void testPermuteArguments() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("permuteArguments");
testPermuteArguments(4, Integer.class, 2, long.class, 6);
if (CAN_TEST_LIGHTLY) return;
testPermuteArguments(4, Integer.class, 2, String.class, 0);
testPermuteArguments(6, Integer.class, 0, null, 30);
//testPermuteArguments(4, Integer.class, 2, long.class, 6); // FIXME Fail_7
}
public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {
if (verbosity >= 2)
......@@ -1354,7 +1404,9 @@ public class MethodHandlesTest {
casStep++;
testPermuteArguments(args, types, outargs, numcases, casStep);
numcases *= inargs;
if (CAN_TEST_LIGHTLY && outargs < max-2) continue;
if (dilution > 10 && outargs >= 4) {
if (CAN_TEST_LIGHTLY) continue;
int[] reorder = new int[outargs];
// Do some special patterns, which we probably missed.
// Replication of a single argument or argument pair.
......@@ -1392,6 +1444,7 @@ public class MethodHandlesTest {
reorder[i] = c % inargs;
c /= inargs;
}
if (CAN_TEST_LIGHTLY && outargs >= 3 && (reorder[0] == reorder[1] || reorder[1] == reorder[2])) continue;
testPermuteArguments(args, types, reorder);
}
}
......@@ -1464,12 +1517,13 @@ public class MethodHandlesTest {
for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 3)
System.out.println("spreadArguments "+argType);
// FIXME: enable _adapter_spread_args and fix Fail_2
for (int nargs = 0; nargs < 10; nargs++) {
if (argType == int.class && nargs >= 6) continue; // FIXME Fail_1
for (int pos = 0; pos < nargs; pos++) {
if (argType == int.class && pos > 0) continue; // FIXME Fail_3
testSpreadArguments(argType, pos, nargs);
for (int nargs = 0; nargs < 50; nargs++) {
if (CAN_TEST_LIGHTLY && nargs > 7) break;
for (int pos = 0; pos <= nargs; pos++) {
if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
continue;
testSpreadArguments(argType, pos, nargs);
}
}
}
......@@ -1557,9 +1611,12 @@ public class MethodHandlesTest {
for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 3)
System.out.println("collectArguments "+argType);
for (int nargs = 0; nargs < 10; nargs++) {
for (int pos = 0; pos < nargs; pos++) {
if (argType == int.class) continue; // FIXME Fail_4
for (int nargs = 0; nargs < 50; nargs++) {
if (CAN_TEST_LIGHTLY && nargs > 7) break;
for (int pos = 0; pos <= nargs; pos++) {
if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
continue;
testCollectArguments(argType, pos, nargs);
}
}
......@@ -1593,10 +1650,15 @@ public class MethodHandlesTest {
public void testInsertArguments() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("insertArguments");
for (int nargs = 0; nargs <= 4; nargs++) {
for (int ins = 0; ins <= 4; ins++) {
if (ins > MAX_ARG_INCREASE) continue; // FIXME Fail_6
for (int nargs = 0; nargs < 50; nargs++) {
if (CAN_TEST_LIGHTLY && nargs > 7) break;
for (int ins = 0; ins <= nargs; ins++) {
if (nargs > 10 && ins > 4 && ins < nargs-4 && ins % 10 != 3)
continue;
for (int pos = 0; pos <= nargs; pos++) {
if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
continue;
if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
testInsertArguments(nargs, pos, ins);
}
}
......@@ -1634,8 +1696,8 @@ public class MethodHandlesTest {
for (Class<?> rtype : new Class[] { Object.class,
List.class,
int.class,
//byte.class, //FIXME: add this
//long.class, //FIXME: add this
byte.class,
long.class,
CharSequence.class,
String.class }) {
testFilterReturnValue(nargs, rtype);
......@@ -1780,6 +1842,7 @@ public class MethodHandlesTest {
// exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker
Set<MethodType> done = new HashSet<MethodType>();
for (int i = 0; i <= 6; i++) {
if (CAN_TEST_LIGHTLY && i > 3) break;
MethodType gtype = MethodType.genericMethodType(i);
for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
for (int j = -1; j < i; j++) {
......@@ -1790,7 +1853,6 @@ public class MethodHandlesTest {
continue;
else
type = type.changeParameterType(j, argType);
if (argType.isPrimitive() && j != i-1) continue; // FIXME Fail_5
if (done.add(type))
testInvokers(type);
MethodType vtype = type.changeReturnType(void.class);
......@@ -1890,6 +1952,7 @@ public class MethodHandlesTest {
}
for (int k = 0; k <= nargs; k++) {
// varargs invoker #0..N
if (CAN_TEST_LIGHTLY && (k > 1 || k < nargs - 1)) continue;
countTest();
calledLog.clear();
inv = MethodHandles.spreadInvoker(type, k);
......@@ -1933,6 +1996,7 @@ public class MethodHandlesTest {
}
private static final String MISSING_ARG = "missingArg";
private static final String MISSING_ARG_2 = "missingArg#2";
static Object targetIfEquals() {
return called("targetIfEquals");
}
......@@ -1968,28 +2032,39 @@ public class MethodHandlesTest {
public void testGuardWithTest() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("guardWithTest");
for (int nargs = 0; nargs <= 3; nargs++) {
if (nargs != 2) continue; // FIXME: test more later
for (int nargs = 0; nargs <= 50; nargs++) {
if (CAN_TEST_LIGHTLY && nargs > 7) break;
testGuardWithTest(nargs, Object.class);
testGuardWithTest(nargs, String.class);
}
}
void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable {
testGuardWithTest(nargs, 0, argClass);
if (nargs <= 5 || nargs % 10 == 3) {
for (int testDrops = 1; testDrops <= nargs; testDrops++)
testGuardWithTest(nargs, testDrops, argClass);
}
}
void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable {
countTest();
int nargs1 = Math.min(3, nargs);
MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class));
MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs));
MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs));
while (test.type().parameterCount() < nargs)
test = MethodHandles.dropArguments(test, test.type().parameterCount()-1, Object.class);
MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1));
MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1));
while (test.type().parameterCount() > nargs)
// 0: test = constant(MISSING_ARG.equals(MISSING_ARG))
// 1: test = lambda (_) MISSING_ARG.equals(_)
test = MethodHandles.insertArguments(test, 0, MISSING_ARG);
if (argClass != Object.class) {
test = changeArgTypes(test, argClass);
target = changeArgTypes(target, argClass);
fallback = changeArgTypes(fallback, argClass);
}
MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback);
assertEquals(target.type(), mh.type());
int testArgs = nargs - testDrops;
assert(testArgs >= 0);
test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass);
target = addTrailingArgs(target, nargs, argClass);
fallback = addTrailingArgs(fallback, nargs, argClass);
Object[][] argLists = {
{ },
{ "foo" }, { MISSING_ARG },
......@@ -1997,7 +2072,19 @@ public class MethodHandlesTest {
{ "foo", "foo", "baz" }, { "foo", "bar", "baz" }
};
for (Object[] argList : argLists) {
if (argList.length != nargs) continue;
Object[] argList1 = argList;
if (argList.length != nargs) {
if (argList.length != nargs1) continue;
argList1 = Arrays.copyOf(argList, nargs);
Arrays.fill(argList1, nargs1, nargs, MISSING_ARG_2);
}
MethodHandle test1 = test;
if (test1.type().parameterCount() > testArgs) {
int pc = test1.type().parameterCount();
test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc));
}
MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback);
assertEquals(target.type(), mh.type());
boolean equals;
switch (nargs) {
case 0: equals = true; break;
......@@ -2007,7 +2094,7 @@ public class MethodHandlesTest {
String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
if (verbosity >= 3)
System.out.println(logEntry(willCall, argList));
Object result = mh.invokeWithArguments(argList);
Object result = mh.invokeWithArguments(argList1);
assertCalled(willCall, argList);
}
}
......@@ -2016,49 +2103,102 @@ public class MethodHandlesTest {
public void testCatchException() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("catchException");
for (int nargs = 2; nargs <= 6; nargs++) {
for (int ti = 0; ti <= 1; ti++) {
boolean throwIt = (ti != 0);
testCatchException(int.class, new ClassCastException("testing"), throwIt, nargs);
testCatchException(void.class, new java.io.IOException("testing"), throwIt, nargs);
testCatchException(String.class, new LinkageError("testing"), throwIt, nargs);
for (int nargs = 0; nargs < 40; nargs++) {
if (CAN_TEST_LIGHTLY && nargs > 7) break;
for (int throwMode = 0; throwMode < THROW_MODE_LIMIT; throwMode++) {
testCatchException(int.class, new ClassCastException("testing"), throwMode, nargs);
if (CAN_TEST_LIGHTLY && nargs > 3) continue;
testCatchException(void.class, new java.io.IOException("testing"), throwMode, nargs);
testCatchException(String.class, new LinkageError("testing"), throwMode, nargs);
}
}
}
static final int THROW_NOTHING = 0, THROW_CAUGHT = 1, THROW_UNCAUGHT = 2, THROW_THROUGH_ADAPTER = 3, THROW_MODE_LIMIT = 4;
void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs) throws Throwable {
testCatchException(returnType, thrown, throwMode, nargs, 0);
if (nargs <= 5 || nargs % 10 == 3) {
for (int catchDrops = 1; catchDrops <= nargs; catchDrops++)
testCatchException(returnType, thrown, throwMode, nargs, catchDrops);
}
}
private static <T extends Throwable>
Object throwOrReturn(Object normal, T exception) throws T {
if (exception != null) throw exception;
if (exception != null) {
called("throwOrReturn/throw", normal, exception);
throw exception;
}
called("throwOrReturn/normal", normal, exception);
return normal;
}
private int fakeIdentityCount;
private Object fakeIdentity(Object x) {
System.out.println("should throw through this!");
fakeIdentityCount++;
return x;
}
void testCatchException(Class<?> returnType, Throwable thrown, boolean throwIt, int nargs) throws Throwable {
void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs, int catchDrops) throws Throwable {
countTest();
if (verbosity >= 3)
System.out.println("catchException rt="+returnType+" throw="+throwIt+" nargs="+nargs);
System.out.println("catchException rt="+returnType+" throw="+throwMode+" nargs="+nargs+" drops="+catchDrops);
Class<? extends Throwable> exType = thrown.getClass();
if (throwMode > THROW_CAUGHT) thrown = new UnsupportedOperationException("do not catch this");
MethodHandle throwOrReturn
= PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
MethodType.methodType(Object.class, Object.class, Throwable.class));
if (throwMode == THROW_THROUGH_ADAPTER) {
MethodHandle fakeIdentity
= PRIVATE.findVirtual(MethodHandlesTest.class, "fakeIdentity",
MethodType.methodType(Object.class, Object.class)).bindTo(this);
for (int i = 0; i < 10; i++)
throwOrReturn = MethodHandles.filterReturnValue(throwOrReturn, fakeIdentity);
}
int nargs1 = Math.max(2, nargs);
MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
while (thrower.type().parameterCount() < nargs)
thrower = MethodHandles.dropArguments(thrower, thrower.type().parameterCount(), Object.class);
MethodHandle catcher = varargsList(1+nargs).asType(MethodType.genericMethodType(1+nargs));
MethodHandle target = MethodHandles.catchException(thrower,
thrown.getClass(), catcher);
thrower = addTrailingArgs(thrower, nargs, Object.class);
int catchArgc = 1 + nargs - catchDrops;
MethodHandle catcher = varargsList(catchArgc).asType(MethodType.genericMethodType(catchArgc));
Object[] args = randomArgs(nargs, Object.class);
Object arg0 = MISSING_ARG;
Object arg1 = (throwMode == THROW_NOTHING) ? (Throwable) null : thrown;
if (nargs > 0) arg0 = args[0];
if (nargs > 1) args[1] = arg1;
assertEquals(nargs1, thrower.type().parameterCount());
if (nargs < nargs1) {
Object[] appendArgs = { arg0, arg1 };
appendArgs = Arrays.copyOfRange(appendArgs, nargs, nargs1);
thrower = MethodHandles.insertArguments(thrower, nargs, appendArgs);
}
assertEquals(nargs, thrower.type().parameterCount());
MethodHandle target = MethodHandles.catchException(thrower, exType, catcher);
assertEquals(thrower.type(), target.type());
assertEquals(nargs, target.type().parameterCount());
//System.out.println("catching with "+target+" : "+throwOrReturn);
Object[] args = randomArgs(nargs, Object.class);
args[1] = (throwIt ? thrown : null);
Object returned = target.invokeWithArguments(args);
Object returned;
try {
returned = target.invokeWithArguments(args);
} catch (Throwable ex) {
assertSame("must get the out-of-band exception", thrown, ex);
if (throwMode <= THROW_CAUGHT)
assertEquals(THROW_UNCAUGHT, throwMode);
returned = ex;
}
assertCalled("throwOrReturn/"+(throwMode == THROW_NOTHING ? "normal" : "throw"), arg0, arg1);
//System.out.println("return from "+target+" : "+returned);
if (!throwIt) {
assertSame(args[0], returned);
} else {
if (throwMode == THROW_NOTHING) {
assertSame(arg0, returned);
} else if (throwMode == THROW_CAUGHT) {
List<Object> catchArgs = new ArrayList<Object>(Arrays.asList(args));
// catcher receives an initial subsequence of target arguments:
catchArgs.subList(nargs - catchDrops, nargs).clear();
// catcher also receives the exception, prepended:
catchArgs.add(0, thrown);
assertEquals(catchArgs, returned);
}
assertEquals(0, fakeIdentityCount);
}
@Test
......@@ -2092,6 +2232,48 @@ public class MethodHandlesTest {
assertSame(thrown, caught);
}
@Test
public void testInterfaceCast() throws Throwable {
for (Class<?> ctype : new Class<?>[]{ Object.class, String.class, CharSequence.class, Number.class, Iterable.class}) {
testInterfaceCast(ctype, false, false);
testInterfaceCast(ctype, true, false);
testInterfaceCast(ctype, false, true);
testInterfaceCast(ctype, true, true);
}
}
public void testInterfaceCast(Class<?> ctype, boolean doret, boolean docast) throws Throwable {
String str = "normal return value";
MethodHandle mh = MethodHandles.identity(String.class);
MethodType mt = mh.type();
if (doret) mt = mt.changeReturnType(ctype);
else mt = mt.changeParameterType(0, ctype);
if (docast) mh = MethodHandles.explicitCastArguments(mh, mt);
else mh = mh.asType(mt);
// this bit is needed to make the interface types disappear for invokeWithArguments:
mh = MethodHandles.explicitCastArguments(mh, mt.generic());
boolean expectFail = !ctype.isInstance(str);
if (ctype.isInterface()) {
// special rules: interfaces slide by more frequently
if (docast || !doret) expectFail = false;
}
Object res;
try {
res = mh.invokeWithArguments(str);
} catch (Exception ex) {
res = ex;
}
boolean sawFail = !(res instanceof String);
if (sawFail != expectFail) {
System.out.println("*** testInterfaceCast: "+mh+" was "+mt+" => "+res+(docast ? " (explicitCastArguments)" : ""));
}
if (!sawFail) {
assertFalse(res.toString(), expectFail);
assertEquals(str, res);
} else {
assertTrue(res.toString(), expectFail);
}
}
@Test
public void testCastFailure() throws Throwable {
if (CAN_SKIP_WORKING) return;
......@@ -2235,46 +2417,105 @@ public class MethodHandlesTest {
called("runForRunnable");
}
public interface Fooable {
Object foo(Fooable x, Object y);
// this is for randomArg:
public class Impl implements Fooable {
public Object foo(Fooable x, Object y) {
throw new RuntimeException("do not call");
}
final String name;
public Impl() { name = "Fooable#"+nextArg(); }
@Override public String toString() { return name; }
}
// overloads:
Object foo(Object x, String y);
List foo(String x, int y);
Object foo(String x);
}
static Object fooForFooable(Fooable x, Object y) {
return called("fooForFooable", x, y);
static Object fooForFooable(String x, Object... y) {
return called("fooForFooable/"+x, y);
}
public static class MyCheckedException extends Exception {
}
public interface WillThrow {
void willThrow() throws MyCheckedException;
}
/*non-public*/ interface PrivateRunnable {
public void run();
}
@Test
public void testAsInstance() throws Throwable {
public void testAsInterfaceInstance() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("testAsInterfaceInstance");
Lookup lookup = MethodHandles.lookup();
// test typical case: Runnable.run
{
countTest();
if (verbosity >= 2) System.out.println("Runnable");
MethodType mt = MethodType.methodType(void.class);
MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt);
Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh);
proxy.run();
assertCalled("runForRunnable");
}
// well known single-name overloaded interface: Appendable.append
{
countTest();
if (verbosity >= 2) System.out.println("Appendable");
ArrayList<List> appendResults = new ArrayList<List>();
MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class));
append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type
MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class);
Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh);
proxy.append("one");
proxy.append("two", 3, 4);
proxy.append('5');
assertEquals(Arrays.asList(Arrays.asList("one"),
Arrays.asList("two", 3, 4),
Arrays.asList('5')),
appendResults);
if (verbosity >= 3) System.out.println("appendResults="+appendResults);
appendResults.clear();
Formatter formatter = new Formatter(proxy);
String fmt = "foo str=%s char='%c' num=%d";
Object[] fmtArgs = { "str!", 'C', 42 };
String expect = String.format(fmt, fmtArgs);
formatter.format(fmt, fmtArgs);
String actual = "";
if (verbosity >= 3) System.out.println("appendResults="+appendResults);
for (List l : appendResults) {
Object x = l.get(0);
switch (l.size()) {
case 1: actual += x; continue;
case 3: actual += ((String)x).substring((int)l.get(1), (int)l.get(2)); continue;
}
actual += l;
}
if (verbosity >= 3) System.out.println("expect="+expect);
if (verbosity >= 3) System.out.println("actual="+actual);
assertEquals(expect, actual);
}
// test case of an single name which is overloaded: Fooable.foo(...)
{
MethodType mt = MethodType.methodType(Object.class, Fooable.class, Object.class);
MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable", mt);
if (verbosity >= 2) System.out.println("Fooable");
MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable",
MethodType.methodType(Object.class, String.class, Object[].class));
Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh);
Object[] args = randomArgs(mt.parameterArray());
Object result = proxy.foo((Fooable) args[0], args[1]);
assertCalled("fooForFooable", args);
assertEquals(result, logEntry("fooForFooable", args));
for (Method m : Fooable.class.getDeclaredMethods()) {
countTest();
assertSame("foo", m.getName());
if (verbosity > 3)
System.out.println("calling "+m);
MethodHandle invoker = lookup.unreflect(m);
MethodType mt = invoker.type();
Class<?>[] types = mt.parameterArray();
types[0] = int.class; // placeholder
Object[] args = randomArgs(types);
args[0] = proxy;
if (verbosity > 3)
System.out.println("calling "+m+" on "+Arrays.asList(args));
Object result = invoker.invokeWithArguments(args);
if (verbosity > 4)
System.out.println("result = "+result);
String name = "fooForFooable/"+args[1];
Object[] argTail = Arrays.copyOfRange(args, 2, args.length);
assertCalled(name, argTail);
assertEquals(result, logEntry(name, argTail));
}
}
// test processing of thrown exceptions:
for (Throwable ex : new Throwable[] { new NullPointerException("ok"),
new InternalError("ok"),
new Throwable("fail"),
......@@ -2285,11 +2526,12 @@ public class MethodHandlesTest {
mh = MethodHandles.insertArguments(mh, 0, ex);
WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh);
try {
countTest();
proxy.willThrow();
System.out.println("Failed to throw: "+ex);
assertTrue(false);
} catch (Throwable ex1) {
if (verbosity > 2) {
if (verbosity > 3) {
System.out.println("throw "+ex);
System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1));
}
......@@ -2308,16 +2550,49 @@ public class MethodHandlesTest {
}
}
}
// Test error checking:
for (Class<?> nonSAM : new Class[] { Object.class,
// Test error checking on bad interfaces:
for (Class<?> nonSMI : new Class[] { Object.class,
String.class,
CharSequence.class,
java.io.Serializable.class,
PrivateRunnable.class,
Example.class }) {
if (verbosity > 2) System.out.println(nonSMI.getName());
try {
MethodHandleProxies.asInterfaceInstance(nonSAM, varargsArray(0));
System.out.println("Failed to throw");
assertTrue(false);
countTest(false);
MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0));
assertTrue("Failed to throw on "+nonSMI.getName(), false);
} catch (IllegalArgumentException ex) {
if (verbosity > 2) System.out.println(nonSMI.getSimpleName()+": "+ex);
// Object: java.lang.IllegalArgumentException:
// not a public interface: java.lang.Object
// String: java.lang.IllegalArgumentException:
// not a public interface: java.lang.String
// CharSequence: java.lang.IllegalArgumentException:
// not a single-method interface: java.lang.CharSequence
// Serializable: java.lang.IllegalArgumentException:
// not a single-method interface: java.io.Serializable
// PrivateRunnable: java.lang.IllegalArgumentException:
// not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable
// Example: java.lang.IllegalArgumentException:
// not a public interface: test.java.lang.invoke.MethodHandlesTest$Example
}
}
// Test error checking on interfaces with the wrong method type:
for (Class<?> intfc : new Class[] { Runnable.class /*arity 0*/,
Fooable.class /*arity 1 & 2*/ }) {
int badArity = 1; // known to be incompatible
if (verbosity > 2) System.out.println(intfc.getName());
try {
countTest(false);
MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity));
assertTrue("Failed to throw on "+intfc.getName(), false);
} catch (WrongMethodTypeException ex) {
if (verbosity > 2) System.out.println(intfc.getSimpleName()+": "+ex);
// Runnable: java.lang.invoke.WrongMethodTypeException:
// cannot convert MethodHandle(Object)Object[] to ()void
// Fooable: java.lang.invoke.WrongMethodTypeException:
// cannot convert MethodHandle(Object)Object[] to (Object,String)Object
}
}
}
......
......@@ -82,6 +82,7 @@ public class RicochetTest {
testLongSpreads();
testIntCollects();
testReturns();
testRecursion();
}
@Test
......@@ -371,6 +372,61 @@ public class RicochetTest {
//System.out.println("faultCount="+faultCount);
}
@Test
public void testRecursion() throws Throwable {
if (!startTest("testRecursion")) return;
final int LIMIT = 10;
for (int i = 0; i < LIMIT; i++) {
RFCB rfcb = new RFCB(i);
Object x = "x", y = "y";
Object result = rfcb.recursiveFunction(x, y);
verbose(1, result);
}
}
/** Recursive Function Control Block */
private static class RFCB {
java.util.Random random;
final MethodHandle[] fns;
int depth;
RFCB(int seed) throws Throwable {
this.random = new java.util.Random(seed);
this.fns = new MethodHandle[Math.max(29, (1 << MAX_DEPTH-2)/3)];
java.util.Arrays.fill(fns, lookup().bind(this, "recursiveFunction", genericMethodType(2)));
for (int i = 5; i < fns.length; i++) {
switch (i % 4) {
case 0: fns[i] = filterArguments(fns[i - 5], 0, insertArguments(fns[i - 4], 1, ".")); break;
case 1: fns[i] = filterArguments(fns[i - 5], 1, insertArguments(fns[i - 3], 1, ".")); break;
case 2: fns[i] = filterReturnValue(fns[i - 5], insertArguments(fns[i - 2], 1, ".")); break;
}
}
}
Object recursiveFunction(Object x, Object y) throws Throwable {
depth++;
try {
final int ACTION_COUNT = 11;
switch (random.nextInt(ACTION_COUNT)) {
case 1:
Throwable ex = new RuntimeException();
ex.fillInStackTrace();
if (VERBOSITY >= 2) ex.printStackTrace();
x = "ST; " + x;
break;
case 2:
System.gc();
x = "GC; " + x;
break;
}
boolean isLeaf = (depth >= MAX_DEPTH);
if (isLeaf) {
return Arrays.asList(x, y).toString();
}
return fns[random.nextInt(fns.length)].invokeExact(x, y);
} finally {
depth--;
}
}
}
private static MethodHandle sequence(MethodHandle mh1, MethodHandle... mhs) {
MethodHandle res = mh1;
for (MethodHandle mh2 : mhs)
......@@ -536,6 +592,7 @@ public class RicochetTest {
}
// stress modes:
private static final int MAX_DEPTH = getProperty("MAX_DEPTH", 5);
private static final int REPEAT = getProperty("REPEAT", 0);
private static final int STRESS = getProperty("STRESS", 0);
private static /*v*/ int STRESS_COUNT;
......
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary unit tests for method handles which permute their arguments
* @run junit test.java.lang.invoke.ThrowExceptionsTest
*/
package test.java.lang.invoke;
import org.junit.*;
import java.util.*;
import java.lang.reflect.*;
import java.lang.invoke.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
public class ThrowExceptionsTest {
private static final Class CLASS = ThrowExceptionsTest.class;
private static final Lookup LOOKUP = lookup();
public static void main(String argv[]) throws Throwable {
new ThrowExceptionsTest().testAll((argv.length == 0 ? null : Arrays.asList(argv).toString()));
}
@Test
public void testWMT() throws Throwable {
// mostly call testWMTCallee, but sometimes call its void-returning variant
MethodHandle mh = testWMTCallee();
MethodHandle mh1 = mh.asType(mh.type().changeReturnType(void.class));
assert(mh1 != mh);
testWMT(mh, mh1, 1000);
}
@Test
public void testBoundWMT() throws Throwable {
// mostly call exactInvoker.bindTo(testWMTCallee), but sometimes call its void-returning variant
MethodHandle callee = testWMTCallee();
MethodHandle callee1 = callee.asType(callee.type().changeReturnType(void.class));
MethodHandle invoker = exactInvoker(callee.type());
MethodHandle mh = invoker.bindTo(callee);
MethodHandle mh1 = invoker.bindTo(callee1);
testWMT(mh, mh1, 1000);
}
@Test
public void testFoldWMT() throws Throwable {
// mostly call exactInvoker.fold(constant(testWMTCallee)), but sometimes call its void-returning variant
MethodHandle callee = testWMTCallee();
MethodHandle callee1 = callee.asType(callee.type().changeReturnType(void.class));
MethodHandle invoker = exactInvoker(callee.type());
MethodHandle mh = foldArguments(invoker, constant(MethodHandle.class, callee));
MethodHandle mh1 = foldArguments(invoker, constant(MethodHandle.class, callee1));
testWMT(mh, mh1, 1000);
}
@Test
public void testFoldCCE() throws Throwable {
MethodHandle callee = testWMTCallee();
MethodHandle callee1 = callee.asType(callee.type().changeParameterType(1, Number.class)).asType(callee.type());
MethodHandle invoker = exactInvoker(callee.type());
MethodHandle mh = foldArguments(invoker, constant(MethodHandle.class, callee));
MethodHandle mh1 = foldArguments(invoker, constant(MethodHandle.class, callee1));
testWMT(mh, mh1, 1000);
}
@Test
public void testStackOverflow() throws Throwable {
MethodHandle callee = testWMTCallee();
MethodHandle callee1 = makeStackOverflow().asType(callee.type());
MethodHandle invoker = exactInvoker(callee.type());
MethodHandle mh = foldArguments(invoker, constant(MethodHandle.class, callee));
MethodHandle mh1 = foldArguments(invoker, constant(MethodHandle.class, callee1));
for (int i = 0; i < REPEAT; i++) {
try {
testWMT(mh, mh1, 1000);
} catch (StackOverflowError ex) {
// OK, try again
}
}
}
private static MethodHandle makeStackOverflow() {
MethodType cellType = methodType(void.class);
MethodHandle[] cell = { null }; // recursion point
MethodHandle getCell = insertArguments(arrayElementGetter(cell.getClass()), 0, cell, 0);
MethodHandle invokeCell = foldArguments(exactInvoker(cellType), getCell);
assert(invokeCell.type() == cellType);
cell[0] = invokeCell;
// make it conformable to any type:
invokeCell = dropArguments(invokeCell, 0, Object[].class).asVarargsCollector(Object[].class);
return invokeCell;
}
static int testCases;
private void testAll(String match) throws Throwable {
testCases = 0;
Lookup lookup = lookup();
for (Method m : CLASS.getDeclaredMethods()) {
String name = m.getName();
if (name.startsWith("test") &&
(match == null || match.contains(name.substring("test".length()))) &&
m.getParameterTypes().length == 0 &&
Modifier.isPublic(m.getModifiers()) &&
!Modifier.isStatic(m.getModifiers())) {
System.out.println("["+name+"]");
int tc = testCases;
try {
m.invoke(this);
} catch (Throwable ex) {
System.out.println("*** "+ex);
ex.printStackTrace();
}
if (testCases == tc) testCases++;
}
}
if (testCases == 0) throw new RuntimeException("no test cases found");
System.out.println("ran a total of "+testCases+" test cases");
}
private static MethodHandle findStatic(String name) {
return findMethod(name, true);
}
private static MethodHandle findVirtual(String name) {
return findMethod(name, false);
}
private static MethodHandle findMethod(String name, boolean isStatic) {
MethodHandle mh = null;
for (Method m : CLASS.getDeclaredMethods()) {
if (m.getName().equals(name) &&
Modifier.isStatic(m.getModifiers()) == isStatic) {
if (mh != null)
throw new RuntimeException("duplicate methods: "+name);
try {
mh = LOOKUP.unreflect(m);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
}
}
if (mh == null)
throw new RuntimeException("no method: "+name);
return mh;
}
int testWMTCallee;
private int testWMTCallee(String x) {
return testWMTCallee++;
}
private static MethodHandle testWMTCallee() {
MethodHandle callee = findVirtual("testWMTCallee");
// FIXME: should not have to retype callee
callee = callee.asType(callee.type().changeParameterType(0, Object.class));
return callee;
}
private Exception testWMT(MethodHandle[] mhs, int reps) throws Throwable {
testCases += 1;
testWMTCallee = 0;
int catches = 0;
Exception savedEx = null;
for (int i = 0; i < reps; i++) {
MethodHandle mh = mhs[i % mhs.length];
int n;
try {
// FIXME: should not have to retype this
n = (int) mh.invokeExact((Object)this, "x");
assertEquals(n, i - catches);
// Using the exact type for this causes endless deopt due to
// 'non_cached_result' in SystemDictionary::find_method_handle_invoke.
// The problem is that the compiler thread needs to access a cached
// invoke method, but invoke methods are not cached if one of the
// component types is not on the BCP.
} catch (Exception ex) {
savedEx = ex;
catches++;
}
}
//VERBOSE: System.out.println("reps="+reps+" catches="+catches);
return savedEx;
}
private static final int REPEAT = Integer.getInteger(CLASS.getSimpleName()+".REPEAT", 10);
private Exception testWMT(MethodHandle mh, MethodHandle mh1, int reps) throws Throwable {
//VERBOSE: System.out.println("mh="+mh+" mh1="+mh1);
MethodHandle[] mhs = new MethodHandle[100];
Arrays.fill(mhs, mh);
int patch = mhs.length-1;
Exception savedEx = null;
for (int i = 0; i < REPEAT; i++) {
mhs[patch] = mh;
testWMT(mhs, 10000);
mhs[patch] = mh1;
savedEx = testWMT(mhs, reps);
}
return savedEx;
}
private static void assertEquals(Object x, Object y) {
if (x == y || x != null && x.equals(y)) return;
throw new RuntimeException(x+" != "+y);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册