8139885: implement JEP 274: enhanced method handles

Reviewed-by: jrose, psandoz, vlivanov
This commit is contained in:
Michael Haupt 2015-11-20 15:34:12 +01:00
parent cb8623ad3b
commit 5b2c88e28a
10 changed files with 3297 additions and 131 deletions

View File

@ -872,13 +872,54 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
* @see #asCollector
*/
public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength);
int arity = type().parameterCount();
int spreadArgPos = arity - arrayLength;
return asSpreader(type().parameterCount() - arrayLength, arrayType, arrayLength);
}
/**
* Makes an <em>array-spreading</em> method handle, which accepts an array argument at a given position and spreads
* its elements as positional arguments in place of the array. The new method handle adapts, as its <i>target</i>,
* the current method handle. The type of the adapter will be the same as the type of the target, except that the
* {@code arrayLength} parameters of the target's type, starting at the zero-based position {@code spreadArgPos},
* are replaced by a single array parameter of type {@code arrayType}.
* <p>
* This method behaves very much like {@link #asSpreader(Class, int)}, but accepts an additional {@code spreadArgPos}
* argument to indicate at which position in the parameter list the spreading should take place.
* <p>
* @apiNote Example:
* <blockquote><pre>{@code
MethodHandle compare = LOOKUP.findStatic(Objects.class, "compare", methodType(int.class, Object.class, Object.class, Comparator.class));
MethodHandle compare2FromArray = compare.asSpreader(0, Object[].class, 2);
Object[] ints = new Object[]{3, 9, 7, 7};
Comparator<Integer> cmp = (a, b) -> a - b;
assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 0, 2), cmp) < 0);
assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 1, 3), cmp) > 0);
assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp) == 0);
* }</pre></blockquote>
* @param spreadArgPos the position (zero-based index) in the argument list at which spreading should start.
* @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
* @param arrayLength the number of arguments to spread from an incoming array argument
* @return a new method handle which spreads an array argument at a given position,
* before calling the original method handle
* @throws NullPointerException if {@code arrayType} is a null reference
* @throws IllegalArgumentException if {@code arrayType} is not an array type,
* or if target does not have at least
* {@code arrayLength} parameter types,
* or if {@code arrayLength} is negative,
* or if {@code spreadArgPos} has an illegal value (negative, or together with arrayLength exceeding the
* number of arguments),
* or if the resulting method handle's type would have
* <a href="MethodHandle.html#maxarity">too many parameters</a>
* @throws WrongMethodTypeException if the implied {@code asType} call fails
*
* @see #asSpreader(Class, int)
* @since 9
*/
public MethodHandle asSpreader(int spreadArgPos, Class<?> arrayType, int arrayLength) {
MethodType postSpreadType = asSpreaderChecks(arrayType, spreadArgPos, arrayLength);
MethodHandle afterSpread = this.asType(postSpreadType);
BoundMethodHandle mh = afterSpread.rebind();
LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, spreadArgPos + arrayLength, arrayType);
return mh.copyWith(preSpreadType, lform);
}
@ -886,15 +927,18 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
* See if {@code asSpreader} can be validly called with the given arguments.
* Return the type of the method handle call after spreading but before conversions.
*/
private MethodType asSpreaderChecks(Class<?> arrayType, int arrayLength) {
private MethodType asSpreaderChecks(Class<?> arrayType, int pos, int arrayLength) {
spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount();
if (nargs < arrayLength || arrayLength < 0)
throw newIllegalArgumentException("bad spread array length");
if (pos < 0 || pos + arrayLength > nargs) {
throw newIllegalArgumentException("bad spread position");
}
Class<?> arrayElement = arrayType.getComponentType();
MethodType mtype = type();
boolean match = true, fail = false;
for (int i = nargs - arrayLength; i < nargs; i++) {
for (int i = pos; i < arrayLength; i++) {
Class<?> ptype = mtype.parameterType(i);
if (ptype != arrayElement) {
match = false;
@ -905,7 +949,7 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
}
}
if (match) return mtype;
MethodType needType = mtype.asSpreaderType(arrayType, arrayLength);
MethodType needType = mtype.asSpreaderType(arrayType, pos, arrayLength);
if (!fail) return needType;
// elicit an error:
this.asType(needType);
@ -998,10 +1042,53 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
* @see #asVarargsCollector
*/
public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
asCollectorChecks(arrayType, arrayLength);
int collectArgPos = type().parameterCount() - 1;
return asCollector(type().parameterCount() - 1, arrayType, arrayLength);
}
/**
* Makes an <em>array-collecting</em> method handle, which accepts a given number of positional arguments starting
* at a given position, and collects them into an array argument. The new method handle adapts, as its
* <i>target</i>, the current method handle. The type of the adapter will be the same as the type of the target,
* except that the parameter at the position indicated by {@code collectArgPos} (usually of type {@code arrayType})
* is replaced by {@code arrayLength} parameters whose type is element type of {@code arrayType}.
* <p>
* This method behaves very much like {@link #asCollector(Class, int)}, but differs in that its {@code
* collectArgPos} argument indicates at which position in the parameter list arguments should be collected. This
* index is zero-based.
* <p>
* @apiNote Examples:
* <blockquote><pre>{@code
StringWriter swr = new StringWriter();
MethodHandle swWrite = LOOKUP.findVirtual(StringWriter.class, "write", methodType(void.class, char[].class, int.class, int.class)).bindTo(swr);
MethodHandle swWrite4 = swWrite.asCollector(0, char[].class, 4);
swWrite4.invoke('A', 'B', 'C', 'D', 1, 2);
assertEquals("BC", swr.toString());
swWrite4.invoke('P', 'Q', 'R', 'S', 0, 4);
assertEquals("BCPQRS", swr.toString());
swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);
assertEquals("BCPQRSZ", swr.toString());
* }</pre></blockquote>
* @param collectArgPos the zero-based position in the parameter list at which to start collecting.
* @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
* @param arrayLength the number of arguments to collect into a new array argument
* @return a new method handle which collects some arguments
* into an array, before calling the original method handle
* @throws NullPointerException if {@code arrayType} is a null reference
* @throws IllegalArgumentException if {@code arrayType} is not an array type
* or {@code arrayType} is not assignable to this method handle's array parameter type,
* or {@code arrayLength} is not a legal array size,
* or {@code collectArgPos} has an illegal value (negative, or greater than the number of arguments),
* or the resulting method handle's type would have
* <a href="MethodHandle.html#maxarity">too many parameters</a>
* @throws WrongMethodTypeException if the implied {@code asType} call fails
*
* @see #asCollector(Class, int)
* @since 9
*/
public MethodHandle asCollector(int collectArgPos, Class<?> arrayType, int arrayLength) {
asCollectorChecks(arrayType, collectArgPos, arrayLength);
BoundMethodHandle mh = rebind();
MethodType resultType = type().asCollectorType(arrayType, arrayLength);
MethodType resultType = type().asCollectorType(arrayType, collectArgPos, arrayLength);
MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
if (lform != null) {
@ -1015,15 +1102,18 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
* See if {@code asCollector} can be validly called with the given arguments.
* Return false if the last parameter is not an exact match to arrayType.
*/
/*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
/*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int pos, int arrayLength) {
spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount();
if (nargs != 0) {
Class<?> lastParam = type().parameterType(nargs-1);
if (lastParam == arrayType) return true;
if (lastParam.isAssignableFrom(arrayType)) return false;
if (pos < 0 || pos >= nargs) {
throw newIllegalArgumentException("bad collect position");
}
throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
if (nargs != 0) {
Class<?> param = type().parameterType(pos);
if (param == arrayType) return true;
if (param.isAssignableFrom(arrayType)) return false;
}
throw newIllegalArgumentException("array type not assignable to argument", this, arrayType);
}
/**
@ -1178,7 +1268,7 @@ assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
*/
public MethodHandle asVarargsCollector(Class<?> arrayType) {
Objects.requireNonNull(arrayType);
boolean lastMatch = asCollectorChecks(arrayType, 0);
boolean lastMatch = asCollectorChecks(arrayType, type().parameterCount() - 1, 0);
if (isVarargsCollector() && lastMatch)
return this;
return MethodHandleImpl.makeVarargsCollector(this, arrayType);
@ -1341,7 +1431,6 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
// cannot be cracked into MethodHandleInfo.
assert viewAsTypeChecks(newType, strict);
BoundMethodHandle mh = rebind();
assert(!((MethodHandle)mh instanceof DirectMethodHandle));
return mh.copyWith(newType, mh.form);
}

View File

@ -27,16 +27,17 @@ package java.lang.invoke;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
import jdk.internal.HotSpotIntrinsicCandidate;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import static java.lang.invoke.LambdaForm.*;
@ -1297,7 +1298,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@Override
public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
if (intrinsicName == Intrinsic.IDENTITY) {
MethodType resultType = type().asCollectorType(arrayType, arrayLength);
MethodType resultType = type().asCollectorType(arrayType, type().parameterCount() - 1, arrayLength);
MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
return newArray.asType(resultType);
}
@ -1619,17 +1620,251 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
}
/**
* Assembles a loop method handle from the given handles and type information. This works by binding and configuring
* the {@linkplain #looper(MethodHandle[], MethodHandle[], MethodHandle[], MethodHandle[], int, int, Object[]) "most
* generic loop"}.
*
* @param tloop the return type of the loop.
* @param targs types of the arguments to be passed to the loop.
* @param tvars types of loop-local variables.
* @param init sanitized array of initializers for loop-local variables.
* @param step sanitited array of loop bodies.
* @param pred sanitized array of predicates.
* @param fini sanitized array of loop finalizers.
*
* @return a handle that, when invoked, will execute the loop.
*/
static MethodHandle makeLoop(Class<?> tloop, List<Class<?>> targs, List<Class<?>> tvars, List<MethodHandle> init,
List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini) {
MethodHandle[] ainit = toArrayArgs(init);
MethodHandle[] astep = toArrayArgs(step);
MethodHandle[] apred = toArrayArgs(pred);
MethodHandle[] afini = toArrayArgs(fini);
MethodHandle l = getConstantHandle(MH_looper);
// Bind the statically known arguments.
l = MethodHandles.insertArguments(l, 0, ainit, astep, apred, afini, tvars.size(), targs.size());
// Turn the args array into an argument list.
l = l.asCollector(Object[].class, targs.size());
// Finally, make loop type.
MethodType loopType = MethodType.methodType(tloop, targs);
l = l.asType(loopType);
return l;
}
/**
* Converts all handles in the {@code hs} array to handles that accept an array of arguments.
*
* @param hs method handles to be converted.
*
* @return the {@code hs} array, with all method handles therein converted.
*/
static MethodHandle[] toArrayArgs(List<MethodHandle> hs) {
return hs.stream().map(h -> h.asSpreader(Object[].class, h.type().parameterCount())).toArray(MethodHandle[]::new);
}
/**
* This method embodies the most generic loop for use by {@link MethodHandles#loop(MethodHandle[][])}. A handle on
* it will be transformed into a handle on a concrete loop instantiation by {@link #makeLoop}.
*
* @param init loop-local variable initializers.
* @param step bodies.
* @param pred predicates.
* @param fini finalizers.
* @param varSize number of loop-local variables.
* @param nArgs number of arguments passed to the loop.
* @param args arguments to the loop invocation.
*
* @return the result of executing the loop.
*/
static Object looper(MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini,
int varSize, int nArgs, Object[] args) throws Throwable {
Object[] varsAndArgs = new Object[varSize + nArgs];
for (int i = 0, v = 0; i < init.length; ++i) {
if (init[i].type().returnType() == void.class) {
init[i].invoke(args);
} else {
varsAndArgs[v++] = init[i].invoke(args);
}
}
System.arraycopy(args, 0, varsAndArgs, varSize, nArgs);
final int nSteps = step.length;
for (; ; ) {
for (int i = 0, v = 0; i < nSteps; ++i) {
MethodHandle p = pred[i];
MethodHandle s = step[i];
MethodHandle f = fini[i];
if (s.type().returnType() == void.class) {
s.invoke(varsAndArgs);
} else {
varsAndArgs[v++] = s.invoke(varsAndArgs);
}
if (!(boolean) p.invoke(varsAndArgs)) {
return f.invoke(varsAndArgs);
}
}
}
}
/**
* This method is bound as the predicate in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle,
* MethodHandle) counting loops}.
*
* @param counter the counter parameter, passed in during loop execution.
* @param limit the upper bound of the parameter, statically bound at loop creation time.
*
* @return whether the counter has reached the limit.
*/
static boolean countedLoopPredicate(int counter, int limit) {
return counter <= limit;
}
/**
* This method is bound as the step function in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle,
* MethodHandle) counting loops} to increment the counter.
*
* @param counter the loop counter.
*
* @return the loop counter incremented by 1.
*/
static int countedLoopStep(int counter, int limit) {
return counter + 1;
}
/**
* This is bound to initialize the loop-local iterator in {@linkplain MethodHandles#iteratedLoop iterating loops}.
*
* @param it the {@link Iterable} over which the loop iterates.
*
* @return an {@link Iterator} over the argument's elements.
*/
static Iterator<?> initIterator(Iterable<?> it) {
return it.iterator();
}
/**
* This method is bound as the predicate in {@linkplain MethodHandles#iteratedLoop iterating loops}.
*
* @param it the iterator to be checked.
*
* @return {@code true} iff there are more elements to iterate over.
*/
static boolean iteratePredicate(Iterator<?> it) {
return it.hasNext();
}
/**
* This method is bound as the step for retrieving the current value from the iterator in {@linkplain
* MethodHandles#iteratedLoop iterating loops}.
*
* @param it the iterator.
*
* @return the next element from the iterator.
*/
static Object iterateNext(Iterator<?> it) {
return it.next();
}
/**
* Makes a {@code try-finally} handle that conforms to the type constraints.
*
* @param target the target to execute in a {@code try-finally} block.
* @param cleanup the cleanup to execute in the {@code finally} block.
* @param type the result type of the entire construct.
* @param argTypes the types of the arguments.
*
* @return a handle on the constructed {@code try-finally} block.
*/
static MethodHandle makeTryFinally(MethodHandle target, MethodHandle cleanup, Class<?> type, List<Class<?>> argTypes) {
MethodHandle tf = getConstantHandle(type == void.class ? MH_tryFinallyVoidExec : MH_tryFinallyExec);
// Bind the statically known arguments.
tf = MethodHandles.insertArguments(tf, 0, target, cleanup);
// Turn the args array into an argument list.
tf = tf.asCollector(Object[].class, argTypes.size());
// Finally, make try-finally type.
MethodType tfType = MethodType.methodType(type, argTypes);
tf = tf.asType(tfType);
return tf;
}
/**
* A method that will be bound during construction of a {@code try-finally} handle with non-{@code void} return type
* by {@link MethodHandles#tryFinally(MethodHandle, MethodHandle)}.
*
* @param target the handle to wrap in a {@code try-finally} block. This will be bound.
* @param cleanup the handle to run in any case before returning. This will be bound.
* @param args the arguments to the call. These will remain as the argument list.
*
* @return whatever the execution of the {@code target} returned (it may have been modified by the execution of
* {@code cleanup}).
* @throws Throwable in case anything is thrown by the execution of {@code target}, the {@link Throwable} will be
* passed to the {@code cleanup} handle, which may decide to throw any exception it sees fit.
*/
static Object tryFinallyExecutor(MethodHandle target, MethodHandle cleanup, Object[] args) throws Throwable {
Throwable t = null;
Object r = null;
try {
r = target.invoke(args);
} catch (Throwable thrown) {
t = thrown;
throw t;
} finally {
r = cleanup.invoke(t, r, args);
}
return r;
}
/**
* A method that will be bound during construction of a {@code try-finally} handle with {@code void} return type by
* {@link MethodHandles#tryFinally(MethodHandle, MethodHandle)}.
*
* @param target the handle to wrap in a {@code try-finally} block. This will be bound.
* @param cleanup the handle to run in any case before returning. This will be bound.
* @param args the arguments to the call. These will remain as the argument list.
*
* @throws Throwable in case anything is thrown by the execution of {@code target}, the {@link Throwable} will be
* passed to the {@code cleanup} handle, which may decide to throw any exception it sees fit.
*/
static void tryFinallyVoidExecutor(MethodHandle target, MethodHandle cleanup, Object[] args) throws Throwable {
Throwable t = null;
try {
target.invoke(args);
} catch (Throwable thrown) {
t = thrown;
throw t;
} finally {
cleanup.invoke(t, args);
}
}
// Indexes into constant method handles:
private static final int
static final int
MH_cast = 0,
MH_selectAlternative = 1,
MH_copyAsPrimitiveArray = 2,
MH_fillNewTypedArray = 3,
MH_fillNewArray = 4,
MH_arrayIdentity = 5,
MH_LIMIT = 6;
MH_looper = 6,
MH_countedLoopPred = 7,
MH_countedLoopStep = 8,
MH_iteratePred = 9,
MH_initIterator = 10,
MH_iterateNext = 11,
MH_tryFinallyExec = 12,
MH_tryFinallyVoidExec = 13,
MH_LIMIT = 14;
private static MethodHandle getConstantHandle(int idx) {
static MethodHandle getConstantHandle(int idx) {
MethodHandle handle = HANDLES[idx];
if (handle != null) {
return handle;
@ -1672,6 +1907,31 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return makeIntrinsic(IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
Intrinsic.SELECT_ALTERNATIVE);
case MH_looper:
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "looper", MethodType.methodType(Object.class,
MethodHandle[].class, MethodHandle[].class, MethodHandle[].class, MethodHandle[].class,
int.class, int.class, Object[].class));
case MH_countedLoopPred:
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "countedLoopPredicate",
MethodType.methodType(boolean.class, int.class, int.class));
case MH_countedLoopStep:
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "countedLoopStep",
MethodType.methodType(int.class, int.class, int.class));
case MH_iteratePred:
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iteratePredicate",
MethodType.methodType(boolean.class, Iterator.class));
case MH_initIterator:
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "initIterator",
MethodType.methodType(Iterator.class, Iterable.class));
case MH_iterateNext:
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iterateNext",
MethodType.methodType(Object.class, Iterator.class));
case MH_tryFinallyExec:
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "tryFinallyExecutor",
MethodType.methodType(Object.class, MethodHandle.class, MethodHandle.class, Object[].class));
case MH_tryFinallyVoidExec:
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "tryFinallyVoidExecutor",
MethodType.methodType(void.class, MethodHandle.class, MethodHandle.class, Object[].class));
}
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);

View File

@ -469,12 +469,13 @@ class MethodType implements java.io.Serializable {
/** Replace the last arrayLength parameter types with the component type of arrayType.
* @param arrayType any array type
* @param pos position at which to spread
* @param arrayLength the number of parameter types to change
* @return the resulting type
*/
/*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int arrayLength) {
/*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int pos, int arrayLength) {
assert(parameterCount() >= arrayLength);
int spreadPos = ptypes.length - arrayLength;
int spreadPos = pos;
if (arrayLength == 0) return this; // nothing to change
if (arrayType == Object[].class) {
if (isGeneric()) return this; // nothing to change
@ -489,10 +490,10 @@ class MethodType implements java.io.Serializable {
}
Class<?> elemType = arrayType.getComponentType();
assert(elemType != null);
for (int i = spreadPos; i < ptypes.length; i++) {
for (int i = spreadPos; i < spreadPos + arrayLength; i++) {
if (ptypes[i] != elemType) {
Class<?>[] fixedPtypes = ptypes.clone();
Arrays.fill(fixedPtypes, i, ptypes.length, elemType);
Arrays.fill(fixedPtypes, i, spreadPos + arrayLength, elemType);
return methodType(rtype, fixedPtypes);
}
}
@ -512,12 +513,14 @@ class MethodType implements java.io.Serializable {
/** Delete the last parameter type and replace it with arrayLength copies of the component type of arrayType.
* @param arrayType any array type
* @param pos position at which to insert parameters
* @param arrayLength the number of parameter types to insert
* @return the resulting type
*/
/*non-public*/ MethodType asCollectorType(Class<?> arrayType, int arrayLength) {
/*non-public*/ MethodType asCollectorType(Class<?> arrayType, int pos, int arrayLength) {
assert(parameterCount() >= 1);
assert(lastParameterType().isAssignableFrom(arrayType));
assert(pos < ptypes.length);
assert(ptypes[pos].isAssignableFrom(arrayType));
MethodType res;
if (arrayType == Object[].class) {
res = genericMethodType(arrayLength);
@ -532,7 +535,11 @@ class MethodType implements java.io.Serializable {
if (ptypes.length == 1) {
return res;
} else {
return res.insertParameterTypes(0, parameterList().subList(0, ptypes.length-1));
// insert after (if need be), then before
if (pos < parameterList().size() - 1) {
res = res.insertParameterTypes(arrayLength, parameterList().subList(pos + 1, parameterList().size()));
}
return res.insertParameterTypes(0, parameterList().subList(0, pos));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, 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
@ -225,6 +225,31 @@ public class AccessControlTest {
System.out.println(this+" willAccess "+lc+" m1="+m1+" m2="+m2+" => "+((m2 & m1) != 0));
return (m2 & m1) != 0;
}
/** Predict the success or failure of accessing this class. */
public boolean willAccessClass(Class<?> c2, boolean load) {
Class<?> c1 = lookupClass();
if (load && c1.getClassLoader() == null) {
return false;
}
LookupCase lc = this.in(c2);
int m1 = lc.lookupModes();
boolean r = false;
if (m1 == 0) {
r = false;
} else {
int m2 = fixMods(c2.getModifiers());
if ((m2 & PUBLIC) != 0) {
r = true;
} else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) {
r = true;
}
}
if (verbosity >= 2) {
System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
}
return r;
}
}
private static Class<?> topLevelClass(Class<?> cls) {
@ -342,6 +367,8 @@ public class AccessControlTest {
Method method = targetMethod(targetClass, targetAccess, methodType);
// Try to access target method from various contexts.
for (LookupCase sourceCase : CASES) {
testOneAccess(sourceCase, method, "findClass");
testOneAccess(sourceCase, method, "accessClass");
testOneAccess(sourceCase, method, "find");
testOneAccess(sourceCase, method, "unreflect");
}
@ -356,11 +383,19 @@ public class AccessControlTest {
Class<?> targetClass = method.getDeclaringClass();
String methodName = method.getName();
MethodType methodType = methodType(method.getReturnType(), method.getParameterTypes());
boolean willAccess = sourceCase.willAccess(method);
boolean isFindOrAccessClass = "findClass".equals(kind) || "accessClass".equals(kind);
boolean willAccess = isFindOrAccessClass ?
sourceCase.willAccessClass(targetClass, "findClass".equals(kind)) : sourceCase.willAccess(method);
boolean didAccess = false;
ReflectiveOperationException accessError = null;
try {
switch (kind) {
case "accessClass":
sourceCase.lookup().accessClass(targetClass);
break;
case "findClass":
sourceCase.lookup().findClass(targetClass.getName());
break;
case "find":
if ((method.getModifiers() & Modifier.STATIC) != 0)
sourceCase.lookup().findStatic(targetClass, methodName, methodType);
@ -378,8 +413,8 @@ public class AccessControlTest {
accessError = ex;
}
if (willAccess != didAccess) {
System.out.println(sourceCase+" => "+targetClass.getSimpleName()+"."+methodName+methodType);
System.out.println("fail on "+method+" ex="+accessError);
System.out.println(sourceCase+" => "+targetClass.getSimpleName()+(isFindOrAccessClass?"":"."+methodName+methodType));
System.out.println("fail "+(isFindOrAccessClass?kind:"on "+method)+" ex="+accessError);
assertEquals(willAccess, didAccess);
}
testCount++;

View File

@ -58,6 +58,8 @@ public class BigArityTest {
return x == null ? dflt : x;
}
static final MethodType MT_A = MethodType.methodType(Object.class, Object.class, Object[].class, Object.class);
static Object hashArguments(Object... args) {
return Objects.hash(args);
}
@ -108,9 +110,36 @@ public class BigArityTest {
}
}
// Sizes not in the above array are good:
target.asCollector(Object[].class, minbig-1);
target.asCollector(Object[].class, minbig - 1);
for (int i = 2; i <= 10; i++)
target.asCollector(Object[].class, minbig-i);
target.asCollector(Object[].class, minbig - i);
}
static void asciae02target(Object[] a, Object b) {
// naught
}
@Test
public void asCollectorIAE02() throws ReflectiveOperationException {
final int[] INVALID_ARRAY_LENGTHS = {
Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -2, -1, 254, 255, Integer.MAX_VALUE - 1, Integer.MAX_VALUE
};
MethodHandle target = MethodHandles.lookup().findStatic(BigArityTest.class, "asciae02target",
MethodType.methodType(void.class, Object[].class, Object.class));
int minbig = Integer.MAX_VALUE;
for (int invalidLength : INVALID_ARRAY_LENGTHS) {
if (minbig > invalidLength && invalidLength > 100) minbig = invalidLength;
try {
target.asCollector(0, Object[].class, invalidLength);
assert(false) : invalidLength;
} catch (IllegalArgumentException ex) {
System.out.println("OK: "+ex);
}
}
// Sizes not in the above array are good:
for (int i = 1; i <= 10; ++i) {
target.asCollector(0, Object[].class, minbig - i);
}
}
@Test
@ -216,51 +245,86 @@ public class BigArityTest {
Class<? extends Object[]> cls = (Class<? extends Object[]>) cls0;
//Class<? extends Object[]> cls = Object[].class.asSubclass(cls0);
int nargs = args.length, skip;
Object hr;
MethodHandle smh = mh.asSpreader(cls, nargs - (skip = 0));
MethodHandle hsmh = mh.asSpreader(0, cls, nargs - skip);
Object[] tail = Arrays.copyOfRange(args, skip, nargs, cls);
if (cls == Object[].class)
Object[] head = Arrays.copyOfRange(args, 0, nargs - skip, cls);
if (cls == Object[].class) {
r = smh.invokeExact(tail);
else if (cls == Integer[].class)
hr = hsmh.invokeExact(head);
} else if (cls == Integer[].class) {
r = smh.invokeExact((Integer[]) tail); //warning OK, see 8019340
else
hr = hsmh.invokeExact((Integer[]) head);
} else {
r = smh.invoke(tail);
hr = hsmh.invoke(head);
}
assertEquals(r0, r);
assertEquals(r0, hr);
smh = mh.asSpreader(cls, nargs - (skip = 1));
hsmh = mh.asSpreader(0, cls, nargs - skip);
tail = Arrays.copyOfRange(args, skip, nargs, cls);
if (cls == Object[].class)
head = Arrays.copyOfRange(args, 0, nargs - skip, cls);
if (cls == Object[].class) {
r = smh.invokeExact(args[0], tail);
else if (cls == Integer[].class)
hr = hsmh.invokeExact(head, args[2]);
} else if (cls == Integer[].class) {
r = smh.invokeExact(args[0], (Integer[]) tail);
else
hr = hsmh.invokeExact((Integer[]) head, args[2]);
} else {
r = smh.invoke(args[0], tail);
hr = hsmh.invoke(head, args[2]);
}
assertEquals(r0, r);
assertEquals(r0, hr);
smh = mh.asSpreader(cls, nargs - (skip = 2));
hsmh = mh.asSpreader(0, cls, nargs - skip);
tail = Arrays.copyOfRange(args, skip, nargs, cls);
if (cls == Object[].class)
head = Arrays.copyOfRange(args, 0, nargs - skip, cls);
if (cls == Object[].class) {
r = smh.invokeExact(args[0], args[1], tail);
else if (cls == Integer[].class)
hr = hsmh.invokeExact(head, args[1], args[2]);
} else if (cls == Integer[].class) {
r = smh.invokeExact(args[0], args[1], (Integer[]) tail);
else
hr = hsmh.invokeExact((Integer[]) head, args[1], args[2]);
} else {
r = smh.invoke(args[0], args[1], tail);
hr = hsmh.invoke(head, args[1], args[2]);
}
assertEquals(r0, r);
assertEquals(r0, hr);
smh = mh.asSpreader(cls, nargs - (skip = 3));
hsmh = mh.asSpreader(0, cls, nargs - skip);
tail = Arrays.copyOfRange(args, skip, nargs, cls);
if (cls == Object[].class)
head = Arrays.copyOfRange(args, 0, nargs - skip, cls);
if (cls == Object[].class) {
r = smh.invokeExact(args[0], args[1], args[2], tail);
else if (cls == Integer[].class)
hr = hsmh.invokeExact(head, args[0], args[1], args[2]);
} else if (cls == Integer[].class) {
r = smh.invokeExact(args[0], args[1], args[2], (Integer[]) tail);
else
hr = hsmh.invokeExact((Integer[]) head, args[0], args[1], args[2]);
} else {
r = smh.invoke(args[0], args[1], args[2], tail);
hr = hsmh.invoke(head, args[0], args[1], args[2]);
}
assertEquals(r0, r);
assertEquals(r0, hr);
// Try null array in addition to zero-length array:
tail = null;
if (cls == Object[].class)
head = null;
if (cls == Object[].class) {
r = smh.invokeExact(args[0], args[1], args[2], tail);
else if (cls == Integer[].class)
hr = hsmh.invokeExact(head, args[0], args[1], args[2]);
} else if (cls == Integer[].class) {
r = smh.invokeExact(args[0], args[1], args[2], (Integer[]) tail);
else
hr = hsmh.invokeExact((Integer[]) head, args[0], args[1], args[2]);
} else {
r = smh.invoke(args[0], args[1], args[2], tail);
hr = hsmh.invoke(head, args[0], args[1], args[2]);
}
assertEquals(r0, r);
assertEquals(r0, hr);
}
}
@ -292,7 +356,7 @@ public class BigArityTest {
@Test
public void testArities() throws Throwable {
System.out.println("testing spreaders and collectors on high arities...");
int iterations = ITERATION_COUNT;
int iterations = ITERATION_COUNT;
testArities(Object[].class, MIN_ARITY-10, MIN_ARITY-1, iterations / 1000);
testArities(Object[].class, MIN_ARITY, SLOW_ARITY-1, iterations);
testArities(Object[].class, SLOW_ARITY, MAX_ARITY, iterations / 1000);
@ -307,8 +371,13 @@ public class BigArityTest {
Class<? extends Object[]> cls = (Class<? extends Object[]>) cls0;
System.out.println("array class: "+cls.getSimpleName());
int iterations = ITERATION_COUNT / 1000;
testArities(cls, MIN_ARITY, SLOW_ARITY-1, iterations);
testArities(cls, SLOW_ARITY, MAX_ARITY, iterations / 100);
try {
testArities(cls, MIN_ARITY, SLOW_ARITY - 1, iterations);
testArities(cls, SLOW_ARITY, MAX_ARITY, iterations / 100);
} catch (Throwable t) {
t.printStackTrace();
throw t;
}
}
}
@ -321,11 +390,14 @@ public class BigArityTest {
if (verbose) System.out.println("arity="+arity);
MethodHandle mh = MH_hashArguments(cls, arity);
MethodHandle mh_VA = mh.asSpreader(cls, arity);
MethodHandle mh_VA_h = mh.asSpreader(0, cls, arity-1);
assert(mh_VA.type().parameterType(0) == cls);
testArities(cls, arity, iterations, verbose, mh, mh_VA);
assert(mh_VA_h.type().parameterType(0) == cls);
testArities(cls, arity, iterations, verbose, mh, mh_VA, mh_VA_h);
// mh_CA will collect arguments of a particular type and pass them to mh_VA
MethodHandle mh_CA = mh_VA.asCollector(cls, arity);
MethodHandle mh_VA2 = mh_CA.asSpreader(cls, arity);
MethodHandle mh_VA2_h = mh_CA.asSpreader(0, cls, arity-1);
assert(mh_CA.type().equals(mh.type()));
assert(mh_VA2.type().equals(mh_VA.type()));
if (cls != Object[].class) {
@ -336,7 +408,7 @@ public class BigArityTest {
}
}
int iterations_VA = iterations / 100;
testArities(cls, arity, iterations_VA, false, mh_CA, mh_VA2);
testArities(cls, arity, iterations_VA, false, mh_CA, mh_VA2, mh_VA2_h);
}
}
@ -357,13 +429,16 @@ public class BigArityTest {
* @param verbose are we printing extra output?
* @param mh a fixed-arity version of {@code hashArguments}
* @param mh_VA a variable-arity version of {@code hashArguments}, accepting the given array type {@code cls}
* @param mh_VA_h a version of {@code hashArguments} that has a leading {@code cls} array and one final {@code cls}
* argument
*/
private void testArities(Class<? extends Object[]> cls,
int arity,
int iterations,
boolean verbose,
MethodHandle mh,
MethodHandle mh_VA
MethodHandle mh_VA,
MethodHandle mh_VA_h
) throws Throwable {
if (iterations < 4) iterations = 4;
final int MAX_MH_ARITY = MAX_JVM_ARITY - 1; // mh.invoke(arg*[N])
@ -373,6 +448,7 @@ public class BigArityTest {
args = Arrays.copyOf(args, arity, cls);
Object r0 = Objects.hash(args);
Object r;
Object hr;
MethodHandle ximh = null;
MethodHandle gimh = null;
if (arity <= MAX_INVOKER_ARITY) {
@ -397,13 +473,18 @@ public class BigArityTest {
Object[] mh_args = cat(mh, args);
assert(arity <= MAX_MH_ARITY);
for (int i = 0; i < iterations; ++i) {
if (cls == Object[].class)
if (cls == Object[].class) {
r = mh_VA.invokeExact(args);
else if (cls == Integer[].class)
r = mh_VA.invokeExact((Integer[])args); //warning OK, see 8019340
else
hr = mh_VA_h.invokeExact(Arrays.copyOfRange(args, 0, arity - 1), args[arity - 1]);
} else if (cls == Integer[].class) {
r = mh_VA.invokeExact((Integer[]) args); //warning OK, see 8019340
hr = mh_VA_h.invokeExact((Integer[]) Arrays.copyOfRange(args, 0, arity - 1), (Integer) args[arity - 1]);
} else {
r = mh_VA.invoke(args);
hr = mh_VA_h.invoke(Arrays.copyOfRange(args, 0, arity - 1), args[arity - 1]);
}
assertEquals(r0, r);
assertEquals(r0, hr);
r = mh.invokeWithArguments(args);
assertEquals(r0, r);
if (ximh != null) {
@ -473,6 +554,43 @@ public class BigArityTest {
// </editor-fold>
xF8, xF9, xFA, xFB);
}
static Object hashArguments_252_a(Object x00, Object[] x01_FA, Object xFB) {
return Objects.hash(
// <editor-fold defaultstate="collapsed" desc="x00, x01_FA[0], x01_FA[1], x01_FA[2], ...">
x00, x01_FA[0], x01_FA[1], x01_FA[2], x01_FA[3], x01_FA[4], x01_FA[5], x01_FA[6], x01_FA[7], x01_FA[8],
x01_FA[9], x01_FA[10], x01_FA[11], x01_FA[12], x01_FA[13], x01_FA[14], x01_FA[15], x01_FA[16],
x01_FA[17], x01_FA[18], x01_FA[19], x01_FA[20], x01_FA[21], x01_FA[22], x01_FA[23], x01_FA[24],
x01_FA[25], x01_FA[26], x01_FA[27], x01_FA[28], x01_FA[29], x01_FA[30], x01_FA[31], x01_FA[32],
x01_FA[33], x01_FA[34], x01_FA[35], x01_FA[36], x01_FA[37], x01_FA[38], x01_FA[39], x01_FA[40],
x01_FA[41], x01_FA[42], x01_FA[43], x01_FA[44], x01_FA[45], x01_FA[46], x01_FA[47], x01_FA[48],
x01_FA[49], x01_FA[50], x01_FA[51], x01_FA[52], x01_FA[53], x01_FA[54], x01_FA[55], x01_FA[56],
x01_FA[57], x01_FA[58], x01_FA[59], x01_FA[60], x01_FA[61], x01_FA[62], x01_FA[63], x01_FA[64],
x01_FA[65], x01_FA[66], x01_FA[67], x01_FA[68], x01_FA[69], x01_FA[70], x01_FA[71], x01_FA[72],
x01_FA[73], x01_FA[74], x01_FA[75], x01_FA[76], x01_FA[77], x01_FA[78], x01_FA[79], x01_FA[80],
x01_FA[81], x01_FA[82], x01_FA[83], x01_FA[84], x01_FA[85], x01_FA[86], x01_FA[87], x01_FA[88],
x01_FA[89], x01_FA[90], x01_FA[91], x01_FA[92], x01_FA[93], x01_FA[94], x01_FA[95], x01_FA[96],
x01_FA[97], x01_FA[98], x01_FA[99], x01_FA[100], x01_FA[101], x01_FA[102], x01_FA[103], x01_FA[104],
x01_FA[105], x01_FA[106], x01_FA[107], x01_FA[108], x01_FA[109], x01_FA[110], x01_FA[111], x01_FA[112],
x01_FA[113], x01_FA[114], x01_FA[115], x01_FA[116], x01_FA[117], x01_FA[118], x01_FA[119], x01_FA[120],
x01_FA[121], x01_FA[122], x01_FA[123], x01_FA[124], x01_FA[125], x01_FA[126], x01_FA[127], x01_FA[128],
x01_FA[129], x01_FA[130], x01_FA[131], x01_FA[132], x01_FA[133], x01_FA[134], x01_FA[135], x01_FA[136],
x01_FA[137], x01_FA[138], x01_FA[139], x01_FA[140], x01_FA[141], x01_FA[142], x01_FA[143], x01_FA[144],
x01_FA[145], x01_FA[146], x01_FA[147], x01_FA[148], x01_FA[149], x01_FA[150], x01_FA[151], x01_FA[152],
x01_FA[153], x01_FA[154], x01_FA[155], x01_FA[156], x01_FA[157], x01_FA[158], x01_FA[159], x01_FA[160],
x01_FA[161], x01_FA[162], x01_FA[163], x01_FA[164], x01_FA[165], x01_FA[166], x01_FA[167], x01_FA[168],
x01_FA[169], x01_FA[170], x01_FA[171], x01_FA[172], x01_FA[173], x01_FA[174], x01_FA[175], x01_FA[176],
x01_FA[177], x01_FA[178], x01_FA[179], x01_FA[180], x01_FA[181], x01_FA[182], x01_FA[183], x01_FA[184],
x01_FA[185], x01_FA[186], x01_FA[187], x01_FA[188], x01_FA[189], x01_FA[190], x01_FA[191], x01_FA[192],
x01_FA[193], x01_FA[194], x01_FA[195], x01_FA[196], x01_FA[197], x01_FA[198], x01_FA[199], x01_FA[200],
x01_FA[201], x01_FA[202], x01_FA[203], x01_FA[204], x01_FA[205], x01_FA[206], x01_FA[207], x01_FA[208],
x01_FA[209], x01_FA[210], x01_FA[211], x01_FA[212], x01_FA[213], x01_FA[214], x01_FA[215], x01_FA[216],
x01_FA[217], x01_FA[218], x01_FA[219], x01_FA[220], x01_FA[221], x01_FA[222], x01_FA[223], x01_FA[224],
x01_FA[225], x01_FA[226], x01_FA[227], x01_FA[228], x01_FA[229], x01_FA[230], x01_FA[231], x01_FA[232],
x01_FA[233], x01_FA[234], x01_FA[235], x01_FA[236], x01_FA[237], x01_FA[238], x01_FA[239], x01_FA[240],
x01_FA[241], x01_FA[242], x01_FA[243], x01_FA[244], x01_FA[245], x01_FA[246], x01_FA[247], x01_FA[248],
// </editor-fold>
x01_FA[249], xFB);
}
@Test
public void test252() throws Throwable {
@ -507,6 +625,8 @@ public class BigArityTest {
test252(mh, a, r0);
MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY);
test252(mh_CA, a, r0);
MethodHandle mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-2);
test252(mh_a, a, r0);
}
public void test252(MethodHandle mh, Object[] a, Object r0) throws Throwable {
Object r;
@ -686,6 +806,43 @@ public class BigArityTest {
// </editor-fold>
xF8, xF9, xFA, xFB, xFC);
}
static Object hashArguments_253_a(Object x00, Object[] x01_FB, Object xFC) {
return Objects.hash(
// <editor-fold defaultstate="collapsed" desc="x00, x01_FB[0], x01_FB[1], x01_FB[2], ...">
x00, x01_FB[0], x01_FB[1], x01_FB[2], x01_FB[3], x01_FB[4], x01_FB[5], x01_FB[6], x01_FB[7], x01_FB[8],
x01_FB[9], x01_FB[10], x01_FB[11], x01_FB[12], x01_FB[13], x01_FB[14], x01_FB[15], x01_FB[16],
x01_FB[17], x01_FB[18], x01_FB[19], x01_FB[20], x01_FB[21], x01_FB[22], x01_FB[23], x01_FB[24],
x01_FB[25], x01_FB[26], x01_FB[27], x01_FB[28], x01_FB[29], x01_FB[30], x01_FB[31], x01_FB[32],
x01_FB[33], x01_FB[34], x01_FB[35], x01_FB[36], x01_FB[37], x01_FB[38], x01_FB[39], x01_FB[40],
x01_FB[41], x01_FB[42], x01_FB[43], x01_FB[44], x01_FB[45], x01_FB[46], x01_FB[47], x01_FB[48],
x01_FB[49], x01_FB[50], x01_FB[51], x01_FB[52], x01_FB[53], x01_FB[54], x01_FB[55], x01_FB[56],
x01_FB[57], x01_FB[58], x01_FB[59], x01_FB[60], x01_FB[61], x01_FB[62], x01_FB[63], x01_FB[64],
x01_FB[65], x01_FB[66], x01_FB[67], x01_FB[68], x01_FB[69], x01_FB[70], x01_FB[71], x01_FB[72],
x01_FB[73], x01_FB[74], x01_FB[75], x01_FB[76], x01_FB[77], x01_FB[78], x01_FB[79], x01_FB[80],
x01_FB[81], x01_FB[82], x01_FB[83], x01_FB[84], x01_FB[85], x01_FB[86], x01_FB[87], x01_FB[88],
x01_FB[89], x01_FB[90], x01_FB[91], x01_FB[92], x01_FB[93], x01_FB[94], x01_FB[95], x01_FB[96],
x01_FB[97], x01_FB[98], x01_FB[99], x01_FB[100], x01_FB[101], x01_FB[102], x01_FB[103], x01_FB[104],
x01_FB[105], x01_FB[106], x01_FB[107], x01_FB[108], x01_FB[109], x01_FB[110], x01_FB[111], x01_FB[112],
x01_FB[113], x01_FB[114], x01_FB[115], x01_FB[116], x01_FB[117], x01_FB[118], x01_FB[119], x01_FB[120],
x01_FB[121], x01_FB[122], x01_FB[123], x01_FB[124], x01_FB[125], x01_FB[126], x01_FB[127], x01_FB[128],
x01_FB[129], x01_FB[130], x01_FB[131], x01_FB[132], x01_FB[133], x01_FB[134], x01_FB[135], x01_FB[136],
x01_FB[137], x01_FB[138], x01_FB[139], x01_FB[140], x01_FB[141], x01_FB[142], x01_FB[143], x01_FB[144],
x01_FB[145], x01_FB[146], x01_FB[147], x01_FB[148], x01_FB[149], x01_FB[150], x01_FB[151], x01_FB[152],
x01_FB[153], x01_FB[154], x01_FB[155], x01_FB[156], x01_FB[157], x01_FB[158], x01_FB[159], x01_FB[160],
x01_FB[161], x01_FB[162], x01_FB[163], x01_FB[164], x01_FB[165], x01_FB[166], x01_FB[167], x01_FB[168],
x01_FB[169], x01_FB[170], x01_FB[171], x01_FB[172], x01_FB[173], x01_FB[174], x01_FB[175], x01_FB[176],
x01_FB[177], x01_FB[178], x01_FB[179], x01_FB[180], x01_FB[181], x01_FB[182], x01_FB[183], x01_FB[184],
x01_FB[185], x01_FB[186], x01_FB[187], x01_FB[188], x01_FB[189], x01_FB[190], x01_FB[191], x01_FB[192],
x01_FB[193], x01_FB[194], x01_FB[195], x01_FB[196], x01_FB[197], x01_FB[198], x01_FB[199], x01_FB[200],
x01_FB[201], x01_FB[202], x01_FB[203], x01_FB[204], x01_FB[205], x01_FB[206], x01_FB[207], x01_FB[208],
x01_FB[209], x01_FB[210], x01_FB[211], x01_FB[212], x01_FB[213], x01_FB[214], x01_FB[215], x01_FB[216],
x01_FB[217], x01_FB[218], x01_FB[219], x01_FB[220], x01_FB[221], x01_FB[222], x01_FB[223], x01_FB[224],
x01_FB[225], x01_FB[226], x01_FB[227], x01_FB[228], x01_FB[229], x01_FB[230], x01_FB[231], x01_FB[232],
x01_FB[233], x01_FB[234], x01_FB[235], x01_FB[236], x01_FB[237], x01_FB[238], x01_FB[239], x01_FB[240],
x01_FB[241], x01_FB[242], x01_FB[243], x01_FB[244], x01_FB[245], x01_FB[246], x01_FB[247], x01_FB[248],
// </editor-fold>
x01_FB[249], x01_FB[250], xFC);
}
@Test
public void test253() throws Throwable {
@ -720,6 +877,8 @@ public class BigArityTest {
test253(mh, a, r0);
MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY);
test253(mh_CA, a, r0);
MethodHandle mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-2);
test253(mh_a, a, r0);
}
public void test253(MethodHandle mh, Object[] a, Object r0) throws Throwable {
Object r;
@ -899,6 +1058,43 @@ public class BigArityTest {
// </editor-fold>
xF8, xF9, xFA, xFB, xFC, xFD);
}
static Object hashArguments_254_a(Object x00, Object[] x01_FC, Object xFD) {
return Objects.hash(
// <editor-fold defaultstate="collapsed" desc="x00, x01_FC[0], x01_FC[1], x01_FC[2], ...">
x00, x01_FC[0], x01_FC[1], x01_FC[2], x01_FC[3], x01_FC[4], x01_FC[5], x01_FC[6], x01_FC[7], x01_FC[8],
x01_FC[9], x01_FC[10], x01_FC[11], x01_FC[12], x01_FC[13], x01_FC[14], x01_FC[15], x01_FC[16],
x01_FC[17], x01_FC[18], x01_FC[19], x01_FC[20], x01_FC[21], x01_FC[22], x01_FC[23], x01_FC[24],
x01_FC[25], x01_FC[26], x01_FC[27], x01_FC[28], x01_FC[29], x01_FC[30], x01_FC[31], x01_FC[32],
x01_FC[33], x01_FC[34], x01_FC[35], x01_FC[36], x01_FC[37], x01_FC[38], x01_FC[39], x01_FC[40],
x01_FC[41], x01_FC[42], x01_FC[43], x01_FC[44], x01_FC[45], x01_FC[46], x01_FC[47], x01_FC[48],
x01_FC[49], x01_FC[50], x01_FC[51], x01_FC[52], x01_FC[53], x01_FC[54], x01_FC[55], x01_FC[56],
x01_FC[57], x01_FC[58], x01_FC[59], x01_FC[60], x01_FC[61], x01_FC[62], x01_FC[63], x01_FC[64],
x01_FC[65], x01_FC[66], x01_FC[67], x01_FC[68], x01_FC[69], x01_FC[70], x01_FC[71], x01_FC[72],
x01_FC[73], x01_FC[74], x01_FC[75], x01_FC[76], x01_FC[77], x01_FC[78], x01_FC[79], x01_FC[80],
x01_FC[81], x01_FC[82], x01_FC[83], x01_FC[84], x01_FC[85], x01_FC[86], x01_FC[87], x01_FC[88],
x01_FC[89], x01_FC[90], x01_FC[91], x01_FC[92], x01_FC[93], x01_FC[94], x01_FC[95], x01_FC[96],
x01_FC[97], x01_FC[98], x01_FC[99], x01_FC[100], x01_FC[101], x01_FC[102], x01_FC[103], x01_FC[104],
x01_FC[105], x01_FC[106], x01_FC[107], x01_FC[108], x01_FC[109], x01_FC[110], x01_FC[111], x01_FC[112],
x01_FC[113], x01_FC[114], x01_FC[115], x01_FC[116], x01_FC[117], x01_FC[118], x01_FC[119], x01_FC[120],
x01_FC[121], x01_FC[122], x01_FC[123], x01_FC[124], x01_FC[125], x01_FC[126], x01_FC[127], x01_FC[128],
x01_FC[129], x01_FC[130], x01_FC[131], x01_FC[132], x01_FC[133], x01_FC[134], x01_FC[135], x01_FC[136],
x01_FC[137], x01_FC[138], x01_FC[139], x01_FC[140], x01_FC[141], x01_FC[142], x01_FC[143], x01_FC[144],
x01_FC[145], x01_FC[146], x01_FC[147], x01_FC[148], x01_FC[149], x01_FC[150], x01_FC[151], x01_FC[152],
x01_FC[153], x01_FC[154], x01_FC[155], x01_FC[156], x01_FC[157], x01_FC[158], x01_FC[159], x01_FC[160],
x01_FC[161], x01_FC[162], x01_FC[163], x01_FC[164], x01_FC[165], x01_FC[166], x01_FC[167], x01_FC[168],
x01_FC[169], x01_FC[170], x01_FC[171], x01_FC[172], x01_FC[173], x01_FC[174], x01_FC[175], x01_FC[176],
x01_FC[177], x01_FC[178], x01_FC[179], x01_FC[180], x01_FC[181], x01_FC[182], x01_FC[183], x01_FC[184],
x01_FC[185], x01_FC[186], x01_FC[187], x01_FC[188], x01_FC[189], x01_FC[190], x01_FC[191], x01_FC[192],
x01_FC[193], x01_FC[194], x01_FC[195], x01_FC[196], x01_FC[197], x01_FC[198], x01_FC[199], x01_FC[200],
x01_FC[201], x01_FC[202], x01_FC[203], x01_FC[204], x01_FC[205], x01_FC[206], x01_FC[207], x01_FC[208],
x01_FC[209], x01_FC[210], x01_FC[211], x01_FC[212], x01_FC[213], x01_FC[214], x01_FC[215], x01_FC[216],
x01_FC[217], x01_FC[218], x01_FC[219], x01_FC[220], x01_FC[221], x01_FC[222], x01_FC[223], x01_FC[224],
x01_FC[225], x01_FC[226], x01_FC[227], x01_FC[228], x01_FC[229], x01_FC[230], x01_FC[231], x01_FC[232],
x01_FC[233], x01_FC[234], x01_FC[235], x01_FC[236], x01_FC[237], x01_FC[238], x01_FC[239], x01_FC[240],
x01_FC[241], x01_FC[242], x01_FC[243], x01_FC[244], x01_FC[245], x01_FC[246], x01_FC[247], x01_FC[248],
// </editor-fold>
x01_FC[249], x01_FC[250], x01_FC[251], xFD);
}
@Test
public void test254() throws Throwable {
@ -933,6 +1129,8 @@ public class BigArityTest {
test254(mh, a, r0);
MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY);
test254(mh_CA, a, r0);
MethodHandle mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-2);
test254(mh_a, a, r0);
}
public void test254(MethodHandle mh, Object[] a, Object r0) throws Throwable {
Object r;
@ -1094,6 +1292,43 @@ public class BigArityTest {
// </editor-fold>
xF8, xF9, xFA, xFB, xFC, xFD, xFE);
}
static Object hashArguments_255_a(Object x00, Object[] x01_FD, Object xFE) {
return Objects.hash(
// <editor-fold defaultstate="collapsed" desc="x00, x01_FD[0], x01_FD[1], x01_FD[2], ...">
x00, x01_FD[0], x01_FD[1], x01_FD[2], x01_FD[3], x01_FD[4], x01_FD[5], x01_FD[6], x01_FD[7], x01_FD[8],
x01_FD[9], x01_FD[10], x01_FD[11], x01_FD[12], x01_FD[13], x01_FD[14], x01_FD[15], x01_FD[16],
x01_FD[17], x01_FD[18], x01_FD[19], x01_FD[20], x01_FD[21], x01_FD[22], x01_FD[23], x01_FD[24],
x01_FD[25], x01_FD[26], x01_FD[27], x01_FD[28], x01_FD[29], x01_FD[30], x01_FD[31], x01_FD[32],
x01_FD[33], x01_FD[34], x01_FD[35], x01_FD[36], x01_FD[37], x01_FD[38], x01_FD[39], x01_FD[40],
x01_FD[41], x01_FD[42], x01_FD[43], x01_FD[44], x01_FD[45], x01_FD[46], x01_FD[47], x01_FD[48],
x01_FD[49], x01_FD[50], x01_FD[51], x01_FD[52], x01_FD[53], x01_FD[54], x01_FD[55], x01_FD[56],
x01_FD[57], x01_FD[58], x01_FD[59], x01_FD[60], x01_FD[61], x01_FD[62], x01_FD[63], x01_FD[64],
x01_FD[65], x01_FD[66], x01_FD[67], x01_FD[68], x01_FD[69], x01_FD[70], x01_FD[71], x01_FD[72],
x01_FD[73], x01_FD[74], x01_FD[75], x01_FD[76], x01_FD[77], x01_FD[78], x01_FD[79], x01_FD[80],
x01_FD[81], x01_FD[82], x01_FD[83], x01_FD[84], x01_FD[85], x01_FD[86], x01_FD[87], x01_FD[88],
x01_FD[89], x01_FD[90], x01_FD[91], x01_FD[92], x01_FD[93], x01_FD[94], x01_FD[95], x01_FD[96],
x01_FD[97], x01_FD[98], x01_FD[99], x01_FD[100], x01_FD[101], x01_FD[102], x01_FD[103], x01_FD[104],
x01_FD[105], x01_FD[106], x01_FD[107], x01_FD[108], x01_FD[109], x01_FD[110], x01_FD[111], x01_FD[112],
x01_FD[113], x01_FD[114], x01_FD[115], x01_FD[116], x01_FD[117], x01_FD[118], x01_FD[119], x01_FD[120],
x01_FD[121], x01_FD[122], x01_FD[123], x01_FD[124], x01_FD[125], x01_FD[126], x01_FD[127], x01_FD[128],
x01_FD[129], x01_FD[130], x01_FD[131], x01_FD[132], x01_FD[133], x01_FD[134], x01_FD[135], x01_FD[136],
x01_FD[137], x01_FD[138], x01_FD[139], x01_FD[140], x01_FD[141], x01_FD[142], x01_FD[143], x01_FD[144],
x01_FD[145], x01_FD[146], x01_FD[147], x01_FD[148], x01_FD[149], x01_FD[150], x01_FD[151], x01_FD[152],
x01_FD[153], x01_FD[154], x01_FD[155], x01_FD[156], x01_FD[157], x01_FD[158], x01_FD[159], x01_FD[160],
x01_FD[161], x01_FD[162], x01_FD[163], x01_FD[164], x01_FD[165], x01_FD[166], x01_FD[167], x01_FD[168],
x01_FD[169], x01_FD[170], x01_FD[171], x01_FD[172], x01_FD[173], x01_FD[174], x01_FD[175], x01_FD[176],
x01_FD[177], x01_FD[178], x01_FD[179], x01_FD[180], x01_FD[181], x01_FD[182], x01_FD[183], x01_FD[184],
x01_FD[185], x01_FD[186], x01_FD[187], x01_FD[188], x01_FD[189], x01_FD[190], x01_FD[191], x01_FD[192],
x01_FD[193], x01_FD[194], x01_FD[195], x01_FD[196], x01_FD[197], x01_FD[198], x01_FD[199], x01_FD[200],
x01_FD[201], x01_FD[202], x01_FD[203], x01_FD[204], x01_FD[205], x01_FD[206], x01_FD[207], x01_FD[208],
x01_FD[209], x01_FD[210], x01_FD[211], x01_FD[212], x01_FD[213], x01_FD[214], x01_FD[215], x01_FD[216],
x01_FD[217], x01_FD[218], x01_FD[219], x01_FD[220], x01_FD[221], x01_FD[222], x01_FD[223], x01_FD[224],
x01_FD[225], x01_FD[226], x01_FD[227], x01_FD[228], x01_FD[229], x01_FD[230], x01_FD[231], x01_FD[232],
x01_FD[233], x01_FD[234], x01_FD[235], x01_FD[236], x01_FD[237], x01_FD[238], x01_FD[239], x01_FD[240],
x01_FD[241], x01_FD[242], x01_FD[243], x01_FD[244], x01_FD[245], x01_FD[246], x01_FD[247], x01_FD[248],
// </editor-fold>
x01_FD[249], x01_FD[250], x01_FD[251], x01_FD[252], xFE);
}
@Test
public void test255() throws Throwable {
@ -1163,5 +1398,38 @@ public class BigArityTest {
} catch (IllegalArgumentException ex) {
System.out.println("OK: "+ex);
}
MethodHandle mh_a;
try {
mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-2);
throw new AssertionError("should not create an arity 255 collector method handle");
} catch (IllegalArgumentException ex) {
System.out.println("OK: "+ex);
mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-3);
}
try {
r = mh_a.invokeExact(
// <editor-fold defaultstate="collapsed" desc="a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], ...">
a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], a[0x05], a[0x06], a[0x07], a[0x08], a[0x09], a[0x0A], a[0x0B], a[0x0C], a[0x0D], a[0x0E], a[0x0F],
a[0x10], a[0x11], a[0x12], a[0x13], a[0x14], a[0x15], a[0x16], a[0x17], a[0x18], a[0x19], a[0x1A], a[0x1B], a[0x1C], a[0x1D], a[0x1E], a[0x1F],
a[0x20], a[0x21], a[0x22], a[0x23], a[0x24], a[0x25], a[0x26], a[0x27], a[0x28], a[0x29], a[0x2A], a[0x2B], a[0x2C], a[0x2D], a[0x2E], a[0x2F],
a[0x30], a[0x31], a[0x32], a[0x33], a[0x34], a[0x35], a[0x36], a[0x37], a[0x38], a[0x39], a[0x3A], a[0x3B], a[0x3C], a[0x3D], a[0x3E], a[0x3F],
a[0x40], a[0x41], a[0x42], a[0x43], a[0x44], a[0x45], a[0x46], a[0x47], a[0x48], a[0x49], a[0x4A], a[0x4B], a[0x4C], a[0x4D], a[0x4E], a[0x4F],
a[0x50], a[0x51], a[0x52], a[0x53], a[0x54], a[0x55], a[0x56], a[0x57], a[0x58], a[0x59], a[0x5A], a[0x5B], a[0x5C], a[0x5D], a[0x5E], a[0x5F],
a[0x60], a[0x61], a[0x62], a[0x63], a[0x64], a[0x65], a[0x66], a[0x67], a[0x68], a[0x69], a[0x6A], a[0x6B], a[0x6C], a[0x6D], a[0x6E], a[0x6F],
a[0x70], a[0x71], a[0x72], a[0x73], a[0x74], a[0x75], a[0x76], a[0x77], a[0x78], a[0x79], a[0x7A], a[0x7B], a[0x7C], a[0x7D], a[0x7E], a[0x7F],
a[0x80], a[0x81], a[0x82], a[0x83], a[0x84], a[0x85], a[0x86], a[0x87], a[0x88], a[0x89], a[0x8A], a[0x8B], a[0x8C], a[0x8D], a[0x8E], a[0x8F],
a[0x90], a[0x91], a[0x92], a[0x93], a[0x94], a[0x95], a[0x96], a[0x97], a[0x98], a[0x99], a[0x9A], a[0x9B], a[0x9C], a[0x9D], a[0x9E], a[0x9F],
a[0xA0], a[0xA1], a[0xA2], a[0xA3], a[0xA4], a[0xA5], a[0xA6], a[0xA7], a[0xA8], a[0xA9], a[0xAA], a[0xAB], a[0xAC], a[0xAD], a[0xAE], a[0xAF],
a[0xB0], a[0xB1], a[0xB2], a[0xB3], a[0xB4], a[0xB5], a[0xB6], a[0xB7], a[0xB8], a[0xB9], a[0xBA], a[0xBB], a[0xBC], a[0xBD], a[0xBE], a[0xBF],
a[0xC0], a[0xC1], a[0xC2], a[0xC3], a[0xC4], a[0xC5], a[0xC6], a[0xC7], a[0xC8], a[0xC9], a[0xCA], a[0xCB], a[0xCC], a[0xCD], a[0xCE], a[0xCF],
a[0xD0], a[0xD1], a[0xD2], a[0xD3], a[0xD4], a[0xD5], a[0xD6], a[0xD7], a[0xD8], a[0xD9], a[0xDA], a[0xDB], a[0xDC], a[0xDD], a[0xDE], a[0xDF],
a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF],
a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7],
// </editor-fold>
a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD], a[0xFE]);
throw new AssertionError("should not call an arity 255 collector method handle");
} catch (LinkageError ex) {
System.out.println("OK: "+ex);
}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2015, 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
* @run main/othervm/policy=findclass.security.policy/secure=java.lang.SecurityManager -ea -esa test.java.lang.invoke.FindClassSecurityManager
*/
package test.java.lang.invoke;
import java.lang.invoke.MethodHandles;
public class FindClassSecurityManager {
public static void main(String[] args) throws Throwable {
assert null != System.getSecurityManager();
Class<?> thisClass = FindClassSecurityManager.class;
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class<?> lookedUp = lookup.findClass(thisClass.getName());
assert thisClass == lookedUp;
Class<?> accessed = lookup.accessClass(thisClass);
assert thisClass == accessed;
}
}

View File

@ -32,6 +32,7 @@ package test.java.lang.invoke;
import test.java.lang.invoke.remote.RemoteExample;
import java.lang.invoke.*;
import static java.lang.invoke.MethodType.methodType;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.*;
import java.util.*;
@ -448,6 +449,7 @@ public class MethodHandlesTest {
}
public static interface IntExample {
public void v0();
public default void vd() { called("vd", this); }
public static class Impl implements IntExample {
public void v0() { called("Int/v0", this); }
final String name;
@ -719,9 +721,10 @@ public class MethodHandlesTest {
public void testFindSpecial0() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("findSpecial");
testFindSpecial(SubExample.class, Example.class, void.class, "v0");
testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");
testFindSpecial(SubExample.class, Example.class, void.class, false, "v0");
testFindSpecial(SubExample.class, Example.class, void.class, false, "pkg_v0");
testFindSpecial(RemoteExample.class, PubExample.class, void.class, false, "Pub/pro_v0");
testFindSpecial(Example.class, IntExample.class, void.class, true, "vd");
// Do some negative testing:
for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
@ -729,11 +732,12 @@ public class MethodHandlesTest {
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
testFindSpecial(false, lookup, Example.class, IntExample.class, void.class, "v0");
}
}
void testFindSpecial(Class<?> specialCaller,
Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
Class<?> defc, Class<?> ret, boolean dflt, String name, Class<?>... params) throws Throwable {
if (specialCaller == RemoteExample.class) {
testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params);
testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params);
@ -742,11 +746,11 @@ public class MethodHandlesTest {
testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
return;
}
testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);
testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);
testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);
testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);
testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);
testFindSpecial(false || dflt, PACKAGE, specialCaller, defc, ret, name, params);
testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);
testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
}
void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller,
Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
@ -1834,6 +1838,7 @@ public class MethodHandlesTest {
@Test // SLOW
public void testSpreadArguments() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments0);
CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments1);
}
public void testSpreadArguments0() throws Throwable {
@ -1842,44 +1847,27 @@ public class MethodHandlesTest {
for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 3)
System.out.println("spreadArguments "+argType);
Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
for (int nargs = 0; nargs < 50; nargs++) {
if (CAN_TEST_LIGHTLY && nargs > 11) 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);
testSpreadArguments(argType, arrayType, pos, nargs);
}
}
}
}
public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable {
public void testSpreadArguments(Class<?> argType, Class<?> arrayType, int pos, int nargs) throws Throwable {
countTest();
Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
MethodHandle target2 = varargsArray(arrayType, nargs);
MethodHandle target = target2.asType(target2.type().generic());
if (verbosity >= 3)
System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
Object[] args = randomArgs(target2.type().parameterArray());
// make sure the target does what we think it does:
if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {
Object[] check = (Object[]) target.invokeWithArguments(args);
assertArrayEquals(args, check);
switch (nargs) {
case 0:
check = (Object[]) (Object) target.invokeExact();
assertArrayEquals(args, check);
break;
case 1:
check = (Object[]) (Object) target.invokeExact(args[0]);
assertArrayEquals(args, check);
break;
case 2:
check = (Object[]) (Object) target.invokeExact(args[0], args[1]);
assertArrayEquals(args, check);
break;
}
}
checkTarget(argType, pos, nargs, target, args);
List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
{ // modify newParams in place
List<Class<?>> spreadParams = newParams.subList(pos, nargs);
@ -1898,6 +1886,78 @@ public class MethodHandlesTest {
args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
returnValue = result.invokeWithArguments(args1);
}
checkReturnValue(argType, args, result, returnValue);
}
public void testSpreadArguments1() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("spreadArguments/pos");
for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 3)
System.out.println("spreadArguments "+argType);
Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
for (int nargs = 0; nargs < 50; nargs++) {
if (CAN_TEST_LIGHTLY && nargs > 11) 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;
for (int spr = 1; spr < nargs - pos; ++spr) {
if (spr > 4 && spr != 7 && spr != 11 && spr != 20 && spr < nargs - pos - 4) continue;
testSpreadArguments(argType, arrayType, pos, spr, nargs);
}
}
}
}
}
public void testSpreadArguments(Class<?> argType, Class<?> arrayType, int pos, int spread, int nargs) throws Throwable {
countTest();
MethodHandle target2 = varargsArray(arrayType, nargs);
MethodHandle target = target2.asType(target2.type().generic());
if (verbosity >= 3)
System.out.println("spread into " + target2 + " [" + pos + ".." + (pos + spread) + "[");
Object[] args = randomArgs(target2.type().parameterArray());
// make sure the target does what we think it does:
checkTarget(argType, pos, nargs, target, args);
List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
{ // modify newParams in place
List<Class<?>> spreadParams = newParams.subList(pos, pos + spread);
spreadParams.clear();
spreadParams.add(arrayType);
}
MethodType newType = MethodType.methodType(arrayType, newParams);
MethodHandle result = target2.asSpreader(pos, arrayType, spread);
assert (result.type() == newType) : Arrays.asList(result, newType);
result = result.asType(newType.generic());
// args1 has nargs-spread entries, plus one for the to-be-spread array
int args1Length = nargs - (spread - 1);
Object[] args1 = new Object[args1Length];
System.arraycopy(args, 0, args1, 0, pos);
args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, pos + spread));
System.arraycopy(args, pos + spread, args1, pos + 1, nargs - spread - pos);
Object returnValue = result.invokeWithArguments(args1);
checkReturnValue(argType, args, result, returnValue);
}
private static void checkTarget(Class<?> argType, int pos, int nargs, MethodHandle target, Object[] args) throws Throwable {
if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {
Object[] check = (Object[]) target.invokeWithArguments(args);
assertArrayEquals(args, check);
switch (nargs) {
case 0:
check = (Object[]) (Object) target.invokeExact();
assertArrayEquals(args, check);
break;
case 1:
check = (Object[]) (Object) target.invokeExact(args[0]);
assertArrayEquals(args, check);
break;
case 2:
check = (Object[]) (Object) target.invokeExact(args[0], args[1]);
assertArrayEquals(args, check);
break;
}
}
}
private static void checkReturnValue(Class<?> argType, Object[] args, MethodHandle result, Object returnValue) {
String argstr = Arrays.toString(args);
if (!argType.isPrimitive()) {
Object[] rv = (Object[]) returnValue;
@ -1932,6 +1992,7 @@ public class MethodHandlesTest {
@Test // SLOW
public void testAsCollector() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testAsCollector0);
CodeCacheOverflowProcessor.runMHTest(this::testAsCollector1);
}
public void testAsCollector0() throws Throwable {
@ -1974,6 +2035,51 @@ public class MethodHandlesTest {
// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
assertArrayEquals(collectedArgs, returnValue);
}
public void testAsCollector1() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("asCollector/pos");
for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 3)
System.out.println("asCollector/pos "+argType);
for (int nargs = 0; nargs < 50; nargs++) {
if (CAN_TEST_LIGHTLY && nargs > 11) 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;
for (int coll = 1; coll < nargs - pos; ++coll) {
if (coll > 4 && coll != 7 && coll != 11 && coll != 20 && coll < nargs - pos - 4) continue;
testAsCollector(argType, pos, coll, nargs);
}
}
}
}
}
public void testAsCollector(Class<?> argType, int pos, int collect, int nargs) throws Throwable {
countTest();
// fake up a MH with the same type as the desired adapter:
MethodHandle fake = varargsArray(nargs);
fake = changeArgTypes(fake, argType);
MethodType newType = fake.type();
Object[] args = randomArgs(newType.parameterArray());
// here is what should happen:
// new arg list has "collect" less arguments, but one extra for collected arguments array
int collectedLength = nargs-(collect-1);
Object[] collectedArgs = new Object[collectedLength];
System.arraycopy(args, 0, collectedArgs, 0, pos);
collectedArgs[pos] = Arrays.copyOfRange(args, pos, pos+collect);
System.arraycopy(args, pos+collect, collectedArgs, pos+1, args.length-(pos+collect));
// here is the MH which will witness the collected argument part (not tail!):
MethodHandle target = varargsArray(collectedLength);
target = changeArgTypes(target, 0, pos, argType);
target = changeArgTypes(target, pos, pos+1, Object[].class);
target = changeArgTypes(target, pos+1, collectedLength, argType);
if (verbosity >= 3)
System.out.println("collect "+collect+" from "+Arrays.asList(args)+" ["+pos+".."+(pos+collect)+"[");
MethodHandle result = target.asCollector(pos, Object[].class, collect).asType(newType);
Object[] returnValue = (Object[]) result.invokeWithArguments(args);
assertArrayEquals(collectedArgs, returnValue);
}
@Test // SLOW
public void testInsertArguments() throws Throwable {
@ -2117,21 +2223,29 @@ public class MethodHandlesTest {
public void testCollectArguments0() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("collectArguments");
testFoldOrCollectArguments(true);
testFoldOrCollectArguments(true, false);
}
@Test
public void testFoldArguments() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments0);
CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments1);
}
public void testFoldArguments0() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("foldArguments");
testFoldOrCollectArguments(false);
testFoldOrCollectArguments(false, false);
}
void testFoldOrCollectArguments(boolean isCollect) throws Throwable {
public void testFoldArguments1() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("foldArguments/pos");
testFoldOrCollectArguments(false, true);
}
void testFoldOrCollectArguments(boolean isCollect, boolean withFoldPos) throws Throwable {
assert !(isCollect && withFoldPos); // exclude illegal argument combination
for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) {
for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) {
int maxArity = 10;
@ -2146,7 +2260,7 @@ public class MethodHandlesTest {
if (!mixArgs(argTypes, mix, argTypesSeen)) continue;
for (int collect = 0; collect <= nargs; collect++) {
for (int pos = 0; pos <= nargs - collect; pos++) {
testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect);
testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect, withFoldPos);
}
}
}
@ -2186,13 +2300,14 @@ public class MethodHandlesTest {
int pos, int fold, // position and length of the folded arguments
Class<?> combineType, // type returned from the combiner
Class<?> lastType, // type returned from the target
boolean isCollect) throws Throwable {
boolean isCollect,
boolean withFoldPos) throws Throwable {
int nargs = argTypes.size();
if (pos != 0 && !isCollect) return; // can fold only at pos=0 for now
if (pos != 0 && !isCollect && !withFoldPos) return; // test MethodHandles.foldArguments(MH,MH) only for pos=0
countTest();
List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold);
List<Class<?>> targetArgTypes = new ArrayList<>(argTypes);
if (isCollect) // does targret see arg[pos..pos+cc-1]?
if (isCollect) // does target see arg[pos..pos+cc-1]?
targetArgTypes.subList(pos, pos + fold).clear();
if (combineType != void.class)
targetArgTypes.add(pos, combineType);
@ -2205,7 +2320,7 @@ public class MethodHandlesTest {
if (isCollect)
target2 = MethodHandles.collectArguments(target, pos, combine);
else
target2 = MethodHandles.foldArguments(target, combine);
target2 = withFoldPos ? MethodHandles.foldArguments(target, pos, combine) : MethodHandles.foldArguments(target, combine);
// Simulate expected effect of combiner on arglist:
List<Object> expectedList = new ArrayList<>(argsToPass);
List<Object> argsToFold = expectedList.subList(pos, pos + fold);
@ -2540,6 +2655,203 @@ public class MethodHandlesTest {
}
}
@Test
public void testGenericLoopCombinator() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testGenericLoopCombinator0);
}
public void testGenericLoopCombinator0() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("loop");
// Test as follows:
// * Have an increasing number of loop-local state. Local state type diversity grows with the number.
// * Initializers set the starting value of loop-local state from the corresponding loop argument.
// * For each local state element, there is a predicate - for all state combinations, exercise all predicates.
// * Steps modify each local state element in each iteration.
// * Finalizers group all local state elements into a resulting array. Verify end values.
// * Exercise both pre- and post-checked loops.
// Local state types, start values, predicates, and steps:
// * int a, 0, a < 7, a = a + 1
// * double b, 7.0, b > 0.5, b = b / 2.0
// * String c, "start", c.length <= 9, c = c + a
final Class<?>[] argTypes = new Class<?>[] {int.class, double.class, String.class};
final Object[][] args = new Object[][] {
new Object[]{0 },
new Object[]{0, 7.0 },
new Object[]{0, 7.0, "start"}
};
// These are the expected final state tuples for argument type tuple / predicate combinations, for pre- and
// post-checked loops:
final Object[][] preCheckedResults = new Object[][] {
new Object[]{7 }, // (int) / int
new Object[]{7, 0.0546875 }, // (int,double) / int
new Object[]{5, 0.4375 }, // (int,double) / double
new Object[]{7, 0.0546875, "start1234567"}, // (int,double,String) / int
new Object[]{5, 0.4375, "start1234" }, // (int,double,String) / double
new Object[]{6, 0.109375, "start12345" } // (int,double,String) / String
};
final Object[][] postCheckedResults = new Object[][] {
new Object[]{7 }, // (int) / int
new Object[]{7, 0.109375 }, // (int,double) / int
new Object[]{4, 0.4375 }, // (int,double) / double
new Object[]{7, 0.109375, "start123456"}, // (int,double,String) / int
new Object[]{4, 0.4375, "start123" }, // (int,double,String) / double
new Object[]{5, 0.21875, "start12345" } // (int,double,String) / String
};
final Lookup l = MethodHandles.lookup();
final Class<?> MHT = MethodHandlesTest.class;
final Class<?> B = boolean.class;
final Class<?> I = int.class;
final Class<?> D = double.class;
final Class<?> S = String.class;
final MethodHandle hip = l.findStatic(MHT, "loopIntPred", methodType(B, I));
final MethodHandle hdp = l.findStatic(MHT, "loopDoublePred", methodType(B, I, D));
final MethodHandle hsp = l.findStatic(MHT, "loopStringPred", methodType(B, I, D, S));
final MethodHandle his = l.findStatic(MHT, "loopIntStep", methodType(I, I));
final MethodHandle hds = l.findStatic(MHT, "loopDoubleStep", methodType(D, I, D));
final MethodHandle hss = l.findStatic(MHT, "loopStringStep", methodType(S, I, D, S));
final MethodHandle[] preds = new MethodHandle[] {hip, hdp, hsp};
final MethodHandle[] steps = new MethodHandle[] {his, hds, hss};
for (int nargs = 1, useResultsStart = 0; nargs <= argTypes.length; useResultsStart += nargs++) {
Class<?>[] useArgTypes = Arrays.copyOf(argTypes, nargs, Class[].class);
MethodHandle[] usePreds = Arrays.copyOf(preds, nargs, MethodHandle[].class);
MethodHandle[] useSteps = Arrays.copyOf(steps, nargs, MethodHandle[].class);
Object[] useArgs = args[nargs - 1];
Object[][] usePreCheckedResults = new Object[nargs][];
Object[][] usePostCheckedResults = new Object[nargs][];
System.arraycopy(preCheckedResults, useResultsStart, usePreCheckedResults, 0, nargs);
System.arraycopy(postCheckedResults, useResultsStart, usePostCheckedResults, 0, nargs);
testGenericLoopCombinator(nargs, useArgTypes, usePreds, useSteps, useArgs, usePreCheckedResults,
usePostCheckedResults);
}
}
void testGenericLoopCombinator(int nargs, Class<?>[] argTypes, MethodHandle[] preds, MethodHandle[] steps,
Object[] args, Object[][] preCheckedResults, Object[][] postCheckedResults)
throws Throwable {
List<Class<?>> lArgTypes = Arrays.asList(argTypes);
// Predicate and step handles are passed in as arguments, initializer and finalizer handles are constructed here
// from the available information.
MethodHandle[] inits = new MethodHandle[nargs];
for (int i = 0; i < nargs; ++i) {
MethodHandle h;
// Initializers are meant to return whatever they are passed at a given argument position. This means that
// additional arguments may have to be appended and prepended.
h = MethodHandles.identity(argTypes[i]);
if (i < nargs - 1) {
h = MethodHandles.dropArguments(h, 1, lArgTypes.subList(i + 1, nargs));
}
if (i > 0) {
h = MethodHandles.dropArguments(h, 0, lArgTypes.subList(0, i));
}
inits[i] = h;
}
// Finalizers are all meant to collect all of the loop-local state in a single array and return that. Local
// state is passed before the loop args. Construct such a finalizer by first taking a varargsArray collector for
// the number of local state arguments, and then appending the loop args as to-be-dropped arguments.
MethodHandle[] finis = new MethodHandle[nargs];
MethodHandle genericFini = MethodHandles.dropArguments(
varargsArray(nargs).asType(methodType(Object[].class, lArgTypes)), nargs, lArgTypes);
Arrays.fill(finis, genericFini);
// The predicate and step handles' signatures need to be extended. They currently just accept local state args;
// append possibly missing local state args and loop args using dropArguments.
for (int i = 0; i < nargs; ++i) {
List<Class<?>> additionalLocalStateArgTypes = lArgTypes.subList(i + 1, nargs);
preds[i] = MethodHandles.dropArguments(
MethodHandles.dropArguments(preds[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes);
steps[i] = MethodHandles.dropArguments(
MethodHandles.dropArguments(steps[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes);
}
// Iterate over all of the predicates, using only one of them at a time.
for (int i = 0; i < nargs; ++i) {
MethodHandle[] usePreds;
if (nargs == 1) {
usePreds = preds;
} else {
// Create an all-null preds array, and only use one predicate in this iteration. The null entries will
// be substituted with true predicates by the loop combinator.
usePreds = new MethodHandle[nargs];
usePreds[i] = preds[i];
}
// Go for it.
if (verbosity >= 3) {
System.out.println("calling loop for argument types " + lArgTypes + " with predicate at index " + i);
if (verbosity >= 5) {
System.out.println("predicates: " + Arrays.asList(usePreds));
}
}
MethodHandle[] preInits = new MethodHandle[nargs + 1];
MethodHandle[] prePreds = new MethodHandle[nargs + 1];
MethodHandle[] preSteps = new MethodHandle[nargs + 1];
MethodHandle[] preFinis = new MethodHandle[nargs + 1];
System.arraycopy(inits, 0, preInits, 1, nargs);
System.arraycopy(usePreds, 0, prePreds, 0, nargs); // preds are offset by 1 for pre-checked loops
System.arraycopy(steps, 0, preSteps, 1, nargs);
System.arraycopy(finis, 0, preFinis, 0, nargs); // finis are also offset by 1 for pre-checked loops
// Convert to clause-major form.
MethodHandle[][] preClauses = new MethodHandle[nargs+1][4];
MethodHandle[][] postClauses = new MethodHandle[nargs][4];
toClauseMajor(preClauses, preInits, preSteps, prePreds, preFinis);
toClauseMajor(postClauses, inits, steps, usePreds, finis);
MethodHandle pre = MethodHandles.loop(preClauses);
MethodHandle post = MethodHandles.loop(postClauses);
Object[] preResults = (Object[]) pre.invokeWithArguments(args);
if (verbosity >= 4) {
System.out.println("pre-checked: expected " + Arrays.asList(preCheckedResults[i]) + ", actual " +
Arrays.asList(preResults));
}
Object[] postResults = (Object[]) post.invokeWithArguments(args);
if (verbosity >= 4) {
System.out.println("post-checked: expected " + Arrays.asList(postCheckedResults[i]) + ", actual " +
Arrays.asList(postResults));
}
assertArrayEquals(preCheckedResults[i], preResults);
assertArrayEquals(postCheckedResults[i], postResults);
}
}
static void toClauseMajor(MethodHandle[][] clauses, MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini) {
for (int i = 0; i < clauses.length; ++i) {
clauses[i][0] = init[i];
clauses[i][1] = step[i];
clauses[i][2] = pred[i];
clauses[i][3] = fini[i];
}
}
static boolean loopIntPred(int a) {
if (verbosity >= 5) {
System.out.println("int pred " + a + " -> " + (a < 7));
}
return a < 7;
}
static boolean loopDoublePred(int a, double b) {
if (verbosity >= 5) {
System.out.println("double pred (a=" + a + ") " + b + " -> " + (b > 0.5));
}
return b > 0.5;
}
static boolean loopStringPred(int a, double b, String c) {
if (verbosity >= 5) {
System.out.println("String pred (a=" + a + ",b=" + b + ") " + c + " -> " + (c.length() <= 9));
}
return c.length() <= 9;
}
static int loopIntStep(int a) {
if (verbosity >= 5) {
System.out.println("int step " + a + " -> " + (a + 1));
}
return a + 1;
}
static double loopDoubleStep(int a, double b) {
if (verbosity >= 5) {
System.out.println("double step (a=" + a + ") " + b + " -> " + (b / 2.0));
}
return b / 2.0;
}
static String loopStringStep(int a, double b, String c) {
if (verbosity >= 5) {
System.out.println("String step (a=" + a + ",b=" + b + ") " + c + " -> " + (c + a));
}
return c + a;
}
@Test
public void testThrowException() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testThrowException0);
@ -2575,13 +2887,108 @@ public class MethodHandlesTest {
assertSame(thrown, caught);
}
@Test
public void testTryFinally() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testTryFinally0);
}
public void testTryFinally0() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("tryFinally");
String inputMessage = "returned";
String augmentedMessage = "augmented";
String thrownMessage = "thrown";
String rethrownMessage = "rethrown";
// Test these cases:
// * target returns, cleanup passes through
// * target returns, cleanup augments
// * target throws, cleanup augments and returns
// * target throws, cleanup augments and rethrows
MethodHandle target = MethodHandles.identity(String.class);
MethodHandle targetThrow = MethodHandles.dropArguments(
MethodHandles.throwException(String.class, Exception.class).bindTo(new Exception(thrownMessage)), 0, String.class);
MethodHandle cleanupPassThrough = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0,
Throwable.class, String.class);
MethodHandle cleanupAugment = MethodHandles.dropArguments(MethodHandles.constant(String.class, augmentedMessage),
0, Throwable.class, String.class, String.class);
MethodHandle cleanupCatch = MethodHandles.dropArguments(MethodHandles.constant(String.class, thrownMessage), 0,
Throwable.class, String.class, String.class);
MethodHandle cleanupThrow = MethodHandles.dropArguments(MethodHandles.throwException(String.class, Exception.class).
bindTo(new Exception(rethrownMessage)), 0, Throwable.class, String.class, String.class);
testTryFinally(target, cleanupPassThrough, inputMessage, inputMessage, false);
testTryFinally(target, cleanupAugment, inputMessage, augmentedMessage, false);
testTryFinally(targetThrow, cleanupCatch, inputMessage, thrownMessage, true);
testTryFinally(targetThrow, cleanupThrow, inputMessage, rethrownMessage, true);
// Test the same cases as above for void targets and cleanups.
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class<?> C = this.getClass();
MethodType targetType = methodType(void.class, String[].class);
MethodType cleanupType = methodType(void.class, Throwable.class, String[].class);
MethodHandle vtarget = lookup.findStatic(C, "vtarget", targetType);
MethodHandle vtargetThrow = lookup.findStatic(C, "vtargetThrow", targetType);
MethodHandle vcleanupPassThrough = lookup.findStatic(C, "vcleanupPassThrough", cleanupType);
MethodHandle vcleanupAugment = lookup.findStatic(C, "vcleanupAugment", cleanupType);
MethodHandle vcleanupCatch = lookup.findStatic(C, "vcleanupCatch", cleanupType);
MethodHandle vcleanupThrow = lookup.findStatic(C, "vcleanupThrow", cleanupType);
testTryFinally(vtarget, vcleanupPassThrough, inputMessage, inputMessage, false);
testTryFinally(vtarget, vcleanupAugment, inputMessage, augmentedMessage, false);
testTryFinally(vtargetThrow, vcleanupCatch, inputMessage, thrownMessage, true);
testTryFinally(vtargetThrow, vcleanupThrow, inputMessage, rethrownMessage, true);
}
void testTryFinally(MethodHandle target, MethodHandle cleanup, String input, String msg, boolean mustCatch)
throws Throwable {
countTest();
MethodHandle tf = MethodHandles.tryFinally(target, cleanup);
String result = null;
boolean isVoid = target.type().returnType() == void.class;
String[] argArray = new String[]{input};
try {
if (isVoid) {
tf.invoke(argArray);
} else {
result = (String) tf.invoke(input);
}
} catch (Throwable t) {
assertTrue(mustCatch);
assertEquals(msg, t.getMessage());
return;
}
assertFalse(mustCatch);
if (isVoid) {
assertEquals(msg, argArray[0]);
} else {
assertEquals(msg, result);
}
}
static void vtarget(String[] a) {
// naught, akin to identity
}
static void vtargetThrow(String[] a) throws Exception {
throw new Exception("thrown");
}
static void vcleanupPassThrough(Throwable t, String[] a) {
assertNull(t);
// naught, akin to identity
}
static void vcleanupAugment(Throwable t, String[] a) {
assertNull(t);
a[0] = "augmented";
}
static void vcleanupCatch(Throwable t, String[] a) {
assertNotNull(t);
a[0] = "caught";
}
static void vcleanupThrow(Throwable t, String[] a) throws Exception {
assertNotNull(t);
throw new Exception("rethrown");
}
@Test
public void testInterfaceCast() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testInterfaceCast0);
}
public void testInterfaceCast0() throws Throwable {
//if (CAN_SKIP_WORKING) return;
if (CAN_SKIP_WORKING) return;
startTest("interfaceCast");
assert( (((Object)"foo") instanceof CharSequence));
assert(!(((Object)"foo") instanceof Iterable));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
/*
* Security policy used by the FindClassSecurityManager test.
* Must allow file reads so that jtreg itself can run, and getting class loaders.
*/
grant {
permission java.io.FilePermission "*", "read";
permission java.lang.RuntimePermission "getClassLoader";
};