提交 ff2cda9e 编写于 作者: V vlivanov

8057654: Extract checks performed during MethodHandle construction into separate methods

Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
上级 f7ec9348
...@@ -869,29 +869,34 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray ...@@ -869,29 +869,34 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength); 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); spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount(); int nargs = type().parameterCount();
if (nargs < arrayLength || arrayLength < 0) if (nargs < arrayLength || arrayLength < 0)
throw newIllegalArgumentException("bad spread array length"); throw newIllegalArgumentException("bad spread array length");
if (arrayType != Object[].class && arrayLength != 0) {
boolean sawProblem = false;
Class<?> arrayElement = arrayType.getComponentType(); Class<?> arrayElement = arrayType.getComponentType();
MethodType mtype = type();
boolean match = true, fail = false;
for (int i = nargs - arrayLength; i < nargs; i++) { for (int i = nargs - arrayLength; i < nargs; i++) {
if (!MethodType.canConvert(arrayElement, type().parameterType(i))) { Class<?> ptype = mtype.parameterType(i);
sawProblem = true; if (ptype != arrayElement) {
match = false;
if (!MethodType.canConvert(arrayElement, ptype)) {
fail = true;
break; break;
} }
} }
if (sawProblem) {
ArrayList<Class<?>> ptypes = new ArrayList<>(type().parameterList());
for (int i = nargs - arrayLength; i < nargs; i++) {
ptypes.set(i, arrayElement);
} }
if (match) return mtype;
MethodType needType = mtype.asSpreaderType(arrayType, arrayLength);
if (!fail) return needType;
// elicit an error: // elicit an error:
this.asType(MethodType.methodType(type().returnType(), ptypes)); this.asType(needType);
} throw newInternalError("should not return", null);
}
} }
private void spreadArrayChecks(Class<?> arrayType, int arrayLength) { private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
......
...@@ -2509,32 +2509,36 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY ...@@ -2509,32 +2509,36 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
*/ */
public static public static
MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) { MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
MethodType targetType = target.type(); filterArgumentsCheckArity(target, pos, filters);
MethodHandle adapter = target; 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 int curPos = pos-1; // pre-incremented
for (MethodHandle filter : filters) { for (MethodHandle filter : filters) {
curPos += 1; curPos += 1;
if (filter == null) continue; // ignore null elements of filters if (filter == null) continue; // ignore null elements of filters
adapter = filterArgument(adapter, curPos, filter); adapter = filterArgument(adapter, curPos, filter);
assert((adapterType = adapterType.changeParameterType(curPos, filter.type().parameterType(0))) != null);
} }
assert(adapterType.equals(adapter.type()));
return adapter; return adapter;
} }
/*non-public*/ static /*non-public*/ static
MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) { 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 targetType = target.type();
MethodType filterType = filter.type(); MethodType filterType = filter.type();
if (filterType.parameterCount() != 1 if (filterType.parameterCount() != 1
|| filterType.returnType() != targetType.parameterType(pos)) || filterType.returnType() != targetType.parameterType(pos))
throw newIllegalArgumentException("target and filter types do not match", targetType, filterType); throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
} }
/** /**
...@@ -2714,15 +2718,17 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 ...@@ -2714,15 +2718,17 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) { MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
MethodType targetType = target.type(); MethodType targetType = target.type();
MethodType filterType = filter.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(); Class<?> rtype = targetType.returnType();
int filterValues = filterType.parameterCount(); int filterValues = filterType.parameterCount();
if (filterValues == 0 if (filterValues == 0
? (rtype != void.class) ? (rtype != void.class)
: (rtype != filterType.parameterType(0))) : (rtype != filterType.parameterType(0)))
throw newIllegalArgumentException("target and filter types do not match", target, filter); throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
// result = fold( lambda(retval, arg...) { filter(retval) },
// lambda( arg...) { target(arg...) } )
return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
} }
/** /**
...@@ -2803,24 +2809,28 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); ...@@ -2803,24 +2809,28 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
*/ */
public static public static
MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) { MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
int pos = 0; int foldPos = 0;
MethodType targetType = target.type(); MethodType targetType = target.type();
MethodType combinerType = combiner.type(); MethodType combinerType = combiner.type();
int foldPos = pos; 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(); int foldArgs = combinerType.parameterCount();
int foldVals = combinerType.returnType() == void.class ? 0 : 1; Class<?> rtype = combinerType.returnType();
int foldVals = rtype == void.class ? 0 : 1;
int afterInsertPos = foldPos + foldVals; int afterInsertPos = foldPos + foldVals;
boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs); boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
if (ok && !(combinerType.parameterList() if (ok && !(combinerType.parameterList()
.equals(targetType.parameterList().subList(afterInsertPos, .equals(targetType.parameterList().subList(afterInsertPos,
afterInsertPos + foldArgs)))) afterInsertPos + foldArgs))))
ok = false; ok = false;
if (ok && foldVals != 0 && !combinerType.returnType().equals(targetType.parameterType(0))) if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
ok = false; ok = false;
if (!ok) if (!ok)
throw misMatchedTypes("target and combiner types", targetType, combinerType); throw misMatchedTypes("target and combiner types", targetType, combinerType);
MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos); return rtype;
return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
} }
/** /**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册