8287442: Reduce list to array conversions in java.lang.invoke.MethodHandles

Reviewed-by: jvernee
This commit is contained in:
Claes Redestad 2022-06-08 07:18:29 +00:00
parent 5c39a36641
commit ecf00785f2
3 changed files with 43 additions and 40 deletions
src/java.base/share/classes/java/lang/invoke

@ -973,7 +973,7 @@ abstract class MethodHandleImpl {
int arity = type.parameterCount(); int arity = type.parameterCount();
if (arity > 1) { if (arity > 1) {
MethodHandle mh = throwException(type.dropParameterTypes(1, arity)); MethodHandle mh = throwException(type.dropParameterTypes(1, arity));
mh = MethodHandles.dropArguments(mh, 1, Arrays.copyOfRange(type.parameterArray(), 1, arity)); mh = MethodHandles.dropArgumentsTrusted(mh, 1, Arrays.copyOfRange(type.ptypes(), 1, arity));
return mh; return mh;
} }
return makePairwiseConvert(getFunction(NF_throwException).resolvedHandle(), type, false, true); return makePairwiseConvert(getFunction(NF_throwException).resolvedHandle(), type, false, true);
@ -1941,7 +1941,7 @@ abstract class MethodHandleImpl {
* *
* @return a handle on the constructed {@code try-finally} block. * @return a handle on the constructed {@code try-finally} block.
*/ */
static MethodHandle makeTryFinally(MethodHandle target, MethodHandle cleanup, Class<?> rtype, List<Class<?>> argTypes) { static MethodHandle makeTryFinally(MethodHandle target, MethodHandle cleanup, Class<?> rtype, Class<?>[] argTypes) {
MethodType type = MethodType.methodType(rtype, argTypes); MethodType type = MethodType.methodType(rtype, argTypes);
LambdaForm form = makeTryFinallyForm(type.basicType()); LambdaForm form = makeTryFinallyForm(type.basicType());

@ -5104,7 +5104,7 @@ assert((int)twice.invokeExact(21) == 42);
*/ */
public static MethodHandle empty(MethodType type) { public static MethodHandle empty(MethodType type) {
Objects.requireNonNull(type); Objects.requireNonNull(type);
return dropArguments(zero(type.returnType()), 0, type.parameterList()); return dropArgumentsTrusted(zero(type.returnType()), 0, type.ptypes());
} }
private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT]; private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
@ -5263,14 +5263,10 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
* or if the new method handle's type would have too many parameters * or if the new method handle's type would have too many parameters
*/ */
public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) { public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
return dropArguments0(target, pos, copyTypes(valueTypes.toArray())); return dropArgumentsTrusted(target, pos, valueTypes.toArray(new Class<?>[0]).clone());
} }
private static List<Class<?>> copyTypes(Object[] array) { static MethodHandle dropArgumentsTrusted(MethodHandle target, int pos, Class<?>[] valueTypes) {
return Arrays.asList(Arrays.copyOf(array, array.length, Class[].class));
}
private static MethodHandle dropArguments0(MethodHandle target, int pos, List<Class<?>> valueTypes) {
MethodType oldType = target.type(); // get NPE MethodType oldType = target.type(); // get NPE
int dropped = dropArgumentChecks(oldType, pos, valueTypes); int dropped = dropArgumentChecks(oldType, pos, valueTypes);
MethodType newType = oldType.insertParameterTypes(pos, valueTypes); MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
@ -5285,8 +5281,8 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
return result; return result;
} }
private static int dropArgumentChecks(MethodType oldType, int pos, List<Class<?>> valueTypes) { private static int dropArgumentChecks(MethodType oldType, int pos, Class<?>[] valueTypes) {
int dropped = valueTypes.size(); int dropped = valueTypes.length;
MethodType.checkSlotCount(dropped); MethodType.checkSlotCount(dropped);
int outargs = oldType.parameterCount(); int outargs = oldType.parameterCount();
int inargs = outargs + dropped; int inargs = outargs + dropped;
@ -5344,51 +5340,59 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* <a href="MethodHandle.html#maxarity">too many parameters</a> * <a href="MethodHandle.html#maxarity">too many parameters</a>
*/ */
public static MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) { public static MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
return dropArguments0(target, pos, copyTypes(valueTypes)); return dropArgumentsTrusted(target, pos, valueTypes.clone());
}
/* Convenience overloads for trusting internal low-arity call-sites */
static MethodHandle dropArguments(MethodHandle target, int pos, Class<?> valueType1) {
return dropArgumentsTrusted(target, pos, new Class<?>[] { valueType1 });
}
static MethodHandle dropArguments(MethodHandle target, int pos, Class<?> valueType1, Class<?> valueType2) {
return dropArgumentsTrusted(target, pos, new Class<?>[] { valueType1, valueType2 });
} }
// private version which allows caller some freedom with error handling // private version which allows caller some freedom with error handling
private static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos, private static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, Class<?>[] newTypes, int pos,
boolean nullOnFailure) { boolean nullOnFailure) {
newTypes = copyTypes(newTypes.toArray()); Class<?>[] oldTypes = target.type().ptypes();
List<Class<?>> oldTypes = target.type().parameterList(); int match = oldTypes.length;
int match = oldTypes.size();
if (skip != 0) { if (skip != 0) {
if (skip < 0 || skip > match) { if (skip < 0 || skip > match) {
throw newIllegalArgumentException("illegal skip", skip, target); throw newIllegalArgumentException("illegal skip", skip, target);
} }
oldTypes = oldTypes.subList(skip, match); oldTypes = Arrays.copyOfRange(oldTypes, skip, match);
match -= skip; match -= skip;
} }
List<Class<?>> addTypes = newTypes; Class<?>[] addTypes = newTypes;
int add = addTypes.size(); int add = addTypes.length;
if (pos != 0) { if (pos != 0) {
if (pos < 0 || pos > add) { if (pos < 0 || pos > add) {
throw newIllegalArgumentException("illegal pos", pos, newTypes); throw newIllegalArgumentException("illegal pos", pos, Arrays.toString(newTypes));
} }
addTypes = addTypes.subList(pos, add); addTypes = Arrays.copyOfRange(addTypes, pos, add);
add -= pos; add -= pos;
assert(addTypes.size() == add); assert(addTypes.length == add);
} }
// Do not add types which already match the existing arguments. // Do not add types which already match the existing arguments.
if (match > add || !oldTypes.equals(addTypes.subList(0, match))) { if (match > add || !Arrays.equals(oldTypes, 0, oldTypes.length, addTypes, 0, match)) {
if (nullOnFailure) { if (nullOnFailure) {
return null; return null;
} }
throw newIllegalArgumentException("argument lists do not match", oldTypes, newTypes); throw newIllegalArgumentException("argument lists do not match",
Arrays.toString(oldTypes), Arrays.toString(newTypes));
} }
addTypes = addTypes.subList(match, add); addTypes = Arrays.copyOfRange(addTypes, match, add);
add -= match; add -= match;
assert(addTypes.size() == add); assert(addTypes.length == add);
// newTypes: ( P*[pos], M*[match], A*[add] ) // newTypes: ( P*[pos], M*[match], A*[add] )
// target: ( S*[skip], M*[match] ) // target: ( S*[skip], M*[match] )
MethodHandle adapter = target; MethodHandle adapter = target;
if (add > 0) { if (add > 0) {
adapter = dropArguments0(adapter, skip+ match, addTypes); adapter = dropArgumentsTrusted(adapter, skip+ match, addTypes);
} }
// adapter: (S*[skip], M*[match], A*[add] ) // adapter: (S*[skip], M*[match], A*[add] )
if (pos > 0) { if (pos > 0) {
adapter = dropArguments0(adapter, skip, newTypes.subList(0, pos)); adapter = dropArgumentsTrusted(adapter, skip, Arrays.copyOfRange(newTypes, 0, pos));
} }
// adapter: (S*[skip], P*[pos], M*[match], A*[add] ) // adapter: (S*[skip], P*[pos], M*[match], A*[add] )
return adapter; return adapter;
@ -5452,7 +5456,7 @@ assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));
public static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos) { public static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos) {
Objects.requireNonNull(target); Objects.requireNonNull(target);
Objects.requireNonNull(newTypes); Objects.requireNonNull(newTypes);
return dropArgumentsToMatch(target, skip, newTypes, pos, false); return dropArgumentsToMatch(target, skip, newTypes.toArray(new Class<?>[0]).clone(), pos, false);
} }
/** /**
@ -5771,7 +5775,7 @@ assertEquals("[top, [[up, down, strange], charm], bottom]",
MethodType targetType = target.type(); MethodType targetType = target.type();
MethodType filterType = filter.type(); MethodType filterType = filter.type();
Class<?> rtype = filterType.returnType(); Class<?> rtype = filterType.returnType();
List<Class<?>> filterArgs = filterType.parameterList(); Class<?>[] filterArgs = filterType.ptypes();
if (pos < 0 || (rtype == void.class && pos > targetType.parameterCount()) || if (pos < 0 || (rtype == void.class && pos > targetType.parameterCount()) ||
(rtype != void.class && pos >= targetType.parameterCount())) { (rtype != void.class && pos >= targetType.parameterCount())) {
throw newIllegalArgumentException("position is out of range for target", target, pos); throw newIllegalArgumentException("position is out of range for target", target, pos);
@ -5782,7 +5786,7 @@ assertEquals("[top, [[up, down, strange], charm], bottom]",
if (rtype != targetType.parameterType(pos)) { if (rtype != 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 targetType.dropParameterTypes(pos, pos+1).insertParameterTypes(pos, filterArgs); return targetType.dropParameterTypes(pos, pos + 1).insertParameterTypes(pos, filterArgs);
} }
/** /**
@ -6240,8 +6244,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
throw misMatchedTypes("target and fallback types", ttype, ftype); throw misMatchedTypes("target and fallback types", ttype, ftype);
if (gtype.returnType() != boolean.class) if (gtype.returnType() != boolean.class)
throw newIllegalArgumentException("guard type is not a predicate "+gtype); throw newIllegalArgumentException("guard type is not a predicate "+gtype);
List<Class<?>> targs = ttype.parameterList();
test = dropArgumentsToMatch(test, 0, targs, 0, true); test = dropArgumentsToMatch(test, 0, ttype.ptypes(), 0, true);
if (test == null) { if (test == null) {
throw misMatchedTypes("target and test types", ttype, gtype); throw misMatchedTypes("target and test types", ttype, gtype);
} }
@ -6314,7 +6318,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
throw newIllegalArgumentException("handler does not accept exception type "+exType); throw newIllegalArgumentException("handler does not accept exception type "+exType);
if (htype.returnType() != ttype.returnType()) if (htype.returnType() != ttype.returnType())
throw misMatchedTypes("target and handler return types", ttype, htype); throw misMatchedTypes("target and handler return types", ttype, htype);
handler = dropArgumentsToMatch(handler, 1, ttype.parameterList(), 0, true); handler = dropArgumentsToMatch(handler, 1, ttype.ptypes(), 0, true);
if (handler == null) { if (handler == null) {
throw misMatchedTypes("target and handler types", ttype, htype); throw misMatchedTypes("target and handler types", ttype, htype);
} }
@ -6689,7 +6693,6 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
final List<Class<?>> commonParameterSequence = new ArrayList<>(commonPrefix); final List<Class<?>> commonParameterSequence = new ArrayList<>(commonPrefix);
commonParameterSequence.addAll(commonSuffix); commonParameterSequence.addAll(commonSuffix);
loopChecks2(step, pred, fini, commonParameterSequence); loopChecks2(step, pred, fini, commonParameterSequence);
// Step 3: fill in omitted functions. // Step 3: fill in omitted functions.
for (int i = 0; i < nclauses; ++i) { for (int i = 0; i < nclauses; ++i) {
Class<?> t = iterationVariableTypes.get(i); Class<?> t = iterationVariableTypes.get(i);
@ -6700,7 +6703,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
step.set(i, dropArgumentsToMatch(identityOrVoid(t), 0, commonParameterSequence, i)); step.set(i, dropArgumentsToMatch(identityOrVoid(t), 0, commonParameterSequence, i));
} }
if (pred.get(i) == null) { if (pred.get(i) == null) {
pred.set(i, dropArguments0(constant(boolean.class, true), 0, commonParameterSequence)); pred.set(i, dropArguments(constant(boolean.class, true), 0, commonParameterSequence));
} }
if (fini.get(i) == null) { if (fini.get(i) == null) {
fini.set(i, empty(methodType(t, commonParameterSequence))); fini.set(i, empty(methodType(t, commonParameterSequence)));
@ -6799,7 +6802,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
return hs.stream().map(h -> { return hs.stream().map(h -> {
int pc = h.type().parameterCount(); int pc = h.type().parameterCount();
int tpsize = targetParams.size(); int tpsize = targetParams.size();
return pc < tpsize ? dropArguments0(h, pc, targetParams.subList(pc, tpsize)) : h; return pc < tpsize ? dropArguments(h, pc, targetParams.subList(pc, tpsize)) : h;
}).toList(); }).toList();
} }
@ -7743,7 +7746,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* @since 9 * @since 9
*/ */
public static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup) { public static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup) {
List<Class<?>> targetParamTypes = target.type().parameterList(); Class<?>[] targetParamTypes = target.type().ptypes();
Class<?> rtype = target.type().returnType(); Class<?> rtype = target.type().returnType();
tryFinallyChecks(target, cleanup); tryFinallyChecks(target, cleanup);
@ -7751,7 +7754,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
// Match parameter lists: if the cleanup has a shorter parameter list than the target, add ignored arguments. // Match parameter lists: if the cleanup has a shorter parameter list than the target, add ignored arguments.
// The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the // The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
// target parameter list. // target parameter list.
cleanup = dropArgumentsToMatch(cleanup, (rtype == void.class ? 1 : 2), targetParamTypes, 0); cleanup = dropArgumentsToMatch(cleanup, (rtype == void.class ? 1 : 2), targetParamTypes, 0, false);
// Ensure that the intrinsic type checks the instance thrown by the // Ensure that the intrinsic type checks the instance thrown by the
// target against the first parameter of cleanup // target against the first parameter of cleanup

@ -509,7 +509,7 @@ public final class StringConcatFactory {
// assembled bottom-up, which makes the code arguably hard to read. // assembled bottom-up, which makes the code arguably hard to read.
// Drop all remaining parameter types, leave only helper arguments: // Drop all remaining parameter types, leave only helper arguments:
MethodHandle mh = MethodHandles.dropArguments(newString(), 2, ptypes); MethodHandle mh = MethodHandles.dropArgumentsTrusted(newString(), 2, ptypes);
// Calculate the initialLengthCoder value by looking at all constant values and summing up // Calculate the initialLengthCoder value by looking at all constant values and summing up
// their lengths and adjusting the encoded coder bit if needed // their lengths and adjusting the encoded coder bit if needed