8057654: Extract checks performed during MethodHandle construction into separate methods
Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Wed Sep 10 19:19:51 2014 +0400
@@ -869,29 +869,34 @@
return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
}
- private void asSpreaderChecks(Class<?> arrayType, int arrayLength) {
+ /**
+ * 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) {
spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount();
if (nargs < arrayLength || arrayLength < 0)
throw newIllegalArgumentException("bad spread array length");
- if (arrayType != Object[].class && arrayLength != 0) {
- boolean sawProblem = false;
- Class<?> arrayElement = arrayType.getComponentType();
- for (int i = nargs - arrayLength; i < nargs; i++) {
- if (!MethodType.canConvert(arrayElement, type().parameterType(i))) {
- sawProblem = true;
+ Class<?> arrayElement = arrayType.getComponentType();
+ MethodType mtype = type();
+ boolean match = true, fail = false;
+ for (int i = nargs - arrayLength; i < nargs; i++) {
+ Class<?> ptype = mtype.parameterType(i);
+ if (ptype != arrayElement) {
+ match = false;
+ if (!MethodType.canConvert(arrayElement, ptype)) {
+ fail = true;
break;
}
}
- if (sawProblem) {
- ArrayList<Class<?>> ptypes = new ArrayList<>(type().parameterList());
- for (int i = nargs - arrayLength; i < nargs; i++) {
- ptypes.set(i, arrayElement);
- }
- // elicit an error:
- this.asType(MethodType.methodType(type().returnType(), ptypes));
- }
}
+ if (match) return mtype;
+ MethodType needType = mtype.asSpreaderType(arrayType, arrayLength);
+ if (!fail) return needType;
+ // elicit an error:
+ this.asType(needType);
+ throw newInternalError("should not return", null);
}
private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Sep 10 19:19:51 2014 +0400
@@ -2508,32 +2508,36 @@
*/
public static
MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
- MethodType targetType = target.type();
+ filterArgumentsCheckArity(target, pos, filters);
MethodHandle adapter = target;
- MethodType adapterType = null;
- assert((adapterType = targetType) != null);
- int maxPos = targetType.parameterCount();
- if (pos + filters.length > maxPos)
- throw newIllegalArgumentException("too many filters");
int curPos = pos-1; // pre-incremented
for (MethodHandle filter : filters) {
curPos += 1;
if (filter == null) continue; // ignore null elements of filters
adapter = filterArgument(adapter, curPos, filter);
- assert((adapterType = adapterType.changeParameterType(curPos, filter.type().parameterType(0))) != null);
}
- assert(adapterType.equals(adapter.type()));
return adapter;
}
/*non-public*/ static
MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
+ filterArgumentChecks(target, pos, filter);
+ return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+ }
+
+ private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
+ MethodType targetType = target.type();
+ int maxPos = targetType.parameterCount();
+ if (pos + filters.length > maxPos)
+ throw newIllegalArgumentException("too many filters");
+ }
+
+ private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
MethodType targetType = target.type();
MethodType filterType = filter.type();
if (filterType.parameterCount() != 1
|| filterType.returnType() != targetType.parameterType(pos))
throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
- return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
}
/**
@@ -2713,15 +2717,17 @@
MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
MethodType targetType = target.type();
MethodType filterType = filter.type();
+ filterReturnValueChecks(targetType, filterType);
+ return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
+ }
+
+ private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
Class<?> rtype = targetType.returnType();
int filterValues = filterType.parameterCount();
if (filterValues == 0
? (rtype != void.class)
: (rtype != filterType.parameterType(0)))
- throw newIllegalArgumentException("target and filter types do not match", target, filter);
- // result = fold( lambda(retval, arg...) { filter(retval) },
- // lambda( arg...) { target(arg...) } )
- return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
+ throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
}
/**
@@ -2802,24 +2808,28 @@
*/
public static
MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
- int pos = 0;
+ int foldPos = 0;
MethodType targetType = target.type();
MethodType combinerType = combiner.type();
- int foldPos = pos;
- int foldArgs = combinerType.parameterCount();
- int foldVals = combinerType.returnType() == void.class ? 0 : 1;
+ Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
+ return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
+ }
+
+ private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
+ int foldArgs = combinerType.parameterCount();
+ Class<?> rtype = combinerType.returnType();
+ int foldVals = rtype == void.class ? 0 : 1;
int afterInsertPos = foldPos + foldVals;
boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
if (ok && !(combinerType.parameterList()
.equals(targetType.parameterList().subList(afterInsertPos,
afterInsertPos + foldArgs))))
ok = false;
- if (ok && foldVals != 0 && !combinerType.returnType().equals(targetType.parameterType(0)))
+ if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
ok = false;
if (!ok)
throw misMatchedTypes("target and combiner types", targetType, combinerType);
- MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos);
- return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
+ return rtype;
}
/**