8212726: Replace some use of drop- and foldArguments with filtering argument combinator in StringConcatFactory
Reviewed-by: jlaskey, vlivanov
This commit is contained in:
parent
a633b90085
commit
06a2bb5274
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2018, 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
|
||||
@ -85,7 +85,8 @@ class LambdaFormEditor {
|
||||
PERMUTE_ARGS = 13,
|
||||
LOCAL_TYPES = 14,
|
||||
FOLD_SELECT_ARGS = 15,
|
||||
FOLD_SELECT_ARGS_TO_VOID = 16;
|
||||
FOLD_SELECT_ARGS_TO_VOID = 16,
|
||||
FILTER_SELECT_ARGS = 17;
|
||||
|
||||
private static final boolean STRESS_TEST = false; // turn on to disable most packing
|
||||
private static final int
|
||||
@ -730,21 +731,23 @@ class LambdaFormEditor {
|
||||
Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
|
||||
Object[] combinerArgs = new Object[1 + combinerArity];
|
||||
combinerArgs[0] = getCombiner;
|
||||
Name[] newParams;
|
||||
Name newParam = null;
|
||||
if (keepArguments) {
|
||||
newParams = new Name[0];
|
||||
for (int i = 0; i < combinerArity; i++) {
|
||||
combinerArgs[i + 1] = lambdaForm.parameter(1 + argPositions[i]);
|
||||
assert (basicType(combinerType.parameterType(i)) == lambdaForm.parameterType(1 + argPositions[i]));
|
||||
}
|
||||
} else {
|
||||
newParams = new Name[combinerArity];
|
||||
for (int i = 0; i < newParams.length; i++) {
|
||||
newParams[i] = lambdaForm.parameter(1 + argPositions[i]);
|
||||
newParam = new Name(pos, BasicType.basicType(combinerType.returnType()));
|
||||
for (int i = 0; i < combinerArity; i++) {
|
||||
int argPos = 1 + argPositions[i];
|
||||
if (argPos == pos) {
|
||||
combinerArgs[i + 1] = newParam;
|
||||
} else {
|
||||
combinerArgs[i + 1] = lambdaForm.parameter(argPos);
|
||||
}
|
||||
assert (basicType(combinerType.parameterType(i)) == lambdaForm.parameterType(1 + argPositions[i]));
|
||||
}
|
||||
System.arraycopy(newParams, 0,
|
||||
combinerArgs, 1, combinerArity);
|
||||
}
|
||||
Name callCombiner = new Name(combinerType, combinerArgs);
|
||||
|
||||
@ -755,12 +758,13 @@ class LambdaFormEditor {
|
||||
|
||||
// insert new arguments, if needed
|
||||
int argPos = pos + resultArity; // skip result parameter
|
||||
for (Name newParam : newParams) {
|
||||
if (newParam != null) {
|
||||
buf.insertParameter(argPos++, newParam);
|
||||
exprPos++;
|
||||
}
|
||||
assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length);
|
||||
assert(buf.lastIndexOf(callCombiner) == exprPos+1);
|
||||
if (!dropResult) {
|
||||
buf.replaceParameterByCopy(pos, exprPos+1+newParams.length);
|
||||
buf.replaceParameterByCopy(pos, exprPos+1);
|
||||
}
|
||||
|
||||
return buf.endEdit();
|
||||
@ -845,6 +849,20 @@ class LambdaFormEditor {
|
||||
return putInCache(key, form);
|
||||
}
|
||||
|
||||
LambdaForm filterArgumentsForm(int filterPos, MethodType combinerType, int ... argPositions) {
|
||||
byte kind = Transform.FILTER_SELECT_ARGS;
|
||||
int[] keyArgs = Arrays.copyOf(argPositions, argPositions.length + 1);
|
||||
keyArgs[argPositions.length] = filterPos;
|
||||
Transform key = Transform.of(kind, keyArgs);
|
||||
LambdaForm form = getInCache(key);
|
||||
if (form != null) {
|
||||
assert(form.arity == lambdaForm.arity);
|
||||
return form;
|
||||
}
|
||||
form = makeArgumentCombinationForm(filterPos, combinerType, argPositions, false, false);
|
||||
return putInCache(key, form);
|
||||
}
|
||||
|
||||
LambdaForm permuteArgumentsForm(int skip, int[] reorder) {
|
||||
assert(skip == 1); // skip only the leading MH argument, names[0]
|
||||
int length = lambdaForm.names.length;
|
||||
|
@ -4316,28 +4316,6 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* As {@see foldArguments(MethodHandle, int, MethodHandle)}, but with the
|
||||
* added capability of selecting the arguments from the targets parameters
|
||||
* to call the combiner with. This allows us to avoid some simple cases of
|
||||
* permutations and padding the combiner with dropArguments to select the
|
||||
* right argument, which may ultimately produce fewer intermediaries.
|
||||
*/
|
||||
static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner, int ... argPositions) {
|
||||
MethodType targetType = target.type();
|
||||
MethodType combinerType = combiner.type();
|
||||
Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType, argPositions);
|
||||
BoundMethodHandle result = target.rebind();
|
||||
boolean dropResult = rtype == void.class;
|
||||
LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType(), argPositions);
|
||||
MethodType newType = targetType;
|
||||
if (!dropResult) {
|
||||
newType = newType.dropParameterTypes(pos, pos + 1);
|
||||
}
|
||||
result = result.copyWithExtendL(newType, lform, combiner);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
|
||||
int foldArgs = combinerType.parameterCount();
|
||||
Class<?> rtype = combinerType.returnType();
|
||||
@ -4359,15 +4337,78 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||
return rtype;
|
||||
}
|
||||
|
||||
private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType, int ... argPos) {
|
||||
int foldArgs = combinerType.parameterCount();
|
||||
if (argPos.length != foldArgs) {
|
||||
/**
|
||||
* Adapts a target method handle by pre-processing some of its arguments, then calling the target with the result
|
||||
* of the pre-processing replacing the argument at the given position.
|
||||
*
|
||||
* @param target the method handle to invoke after arguments are combined
|
||||
* @param position the position at which to start folding and at which to insert the folding result; if this is {@code
|
||||
* 0}, the effect is the same as for {@link #foldArguments(MethodHandle, MethodHandle)}.
|
||||
* @param combiner method handle to call initially on the incoming arguments
|
||||
* @param argPositions indexes of the target to pick arguments sent to the combiner from
|
||||
* @return method handle which incorporates the specified argument folding logic
|
||||
* @throws NullPointerException if either argument is null
|
||||
* @throws IllegalArgumentException if either of the following two conditions holds:
|
||||
* (1) {@code combiner}'s return type is not the same as the argument type at position
|
||||
* {@code pos} of the target signature;
|
||||
* (2) the {@code N} argument types at positions {@code argPositions[1...N]} of the target signature are
|
||||
* not identical with the argument types of {@code combiner}.
|
||||
*/
|
||||
/*non-public*/ static MethodHandle filterArgumentsWithCombiner(MethodHandle target, int position, MethodHandle combiner, int ... argPositions) {
|
||||
return argumentsWithCombiner(true, target, position, combiner, argPositions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts a target method handle by pre-processing some of its arguments, calling the target with the result of
|
||||
* the pre-processing inserted into the original sequence of arguments at the given position.
|
||||
*
|
||||
* @param target the method handle to invoke after arguments are combined
|
||||
* @param position the position at which to start folding and at which to insert the folding result; if this is {@code
|
||||
* 0}, the effect is the same as for {@link #foldArguments(MethodHandle, MethodHandle)}.
|
||||
* @param combiner method handle to call initially on the incoming arguments
|
||||
* @param argPositions indexes of the target to pick arguments sent to the combiner from
|
||||
* @return method handle which incorporates the specified argument folding logic
|
||||
* @throws NullPointerException if either argument is null
|
||||
* @throws IllegalArgumentException if either of the following two conditions holds:
|
||||
* (1) {@code combiner}'s return type is non-{@code void} and not the same as the argument type at position
|
||||
* {@code pos} of the target signature;
|
||||
* (2) the {@code N} argument types at positions {@code argPositions[1...N]} of the target signature
|
||||
* (skipping {@code position} where the {@code combiner}'s return will be folded in) are not identical
|
||||
* with the argument types of {@code combiner}.
|
||||
*/
|
||||
/*non-public*/ static MethodHandle foldArgumentsWithCombiner(MethodHandle target, int position, MethodHandle combiner, int ... argPositions) {
|
||||
return argumentsWithCombiner(false, target, position, combiner, argPositions);
|
||||
}
|
||||
|
||||
private static MethodHandle argumentsWithCombiner(boolean filter, MethodHandle target, int position, MethodHandle combiner, int ... argPositions) {
|
||||
MethodType targetType = target.type();
|
||||
MethodType combinerType = combiner.type();
|
||||
Class<?> rtype = argumentsWithCombinerChecks(position, filter, targetType, combinerType, argPositions);
|
||||
BoundMethodHandle result = target.rebind();
|
||||
|
||||
MethodType newType = targetType;
|
||||
LambdaForm lform;
|
||||
if (filter) {
|
||||
lform = result.editor().filterArgumentsForm(1 + position, combinerType.basicType(), argPositions);
|
||||
} else {
|
||||
boolean dropResult = rtype == void.class;
|
||||
lform = result.editor().foldArgumentsForm(1 + position, dropResult, combinerType.basicType(), argPositions);
|
||||
if (!dropResult) {
|
||||
newType = newType.dropParameterTypes(position, position + 1);
|
||||
}
|
||||
}
|
||||
result = result.copyWithExtendL(newType, lform, combiner);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Class<?> argumentsWithCombinerChecks(int position, boolean filter, MethodType targetType, MethodType combinerType, int ... argPos) {
|
||||
int combinerArgs = combinerType.parameterCount();
|
||||
if (argPos.length != combinerArgs) {
|
||||
throw newIllegalArgumentException("combiner and argument map must be equal size", combinerType, argPos.length);
|
||||
}
|
||||
Class<?> rtype = combinerType.returnType();
|
||||
int foldVals = rtype == void.class ? 0 : 1;
|
||||
boolean ok = true;
|
||||
for (int i = 0; i < foldArgs; i++) {
|
||||
|
||||
for (int i = 0; i < combinerArgs; i++) {
|
||||
int arg = argPos[i];
|
||||
if (arg < 0 || arg > targetType.parameterCount()) {
|
||||
throw newIllegalArgumentException("arg outside of target parameterRange", targetType, arg);
|
||||
@ -4378,11 +4419,9 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||
+ " -> " + combinerType + ", map: " + Arrays.toString(argPos));
|
||||
}
|
||||
}
|
||||
if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(foldPos)) {
|
||||
ok = false;
|
||||
}
|
||||
if (!ok)
|
||||
if (filter && combinerType.returnType() != targetType.parameterType(position)) {
|
||||
throw misMatchedTypes("target and combiner types", targetType, combinerType);
|
||||
}
|
||||
return rtype;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2018, 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
|
||||
@ -1533,21 +1533,20 @@ public final class StringConcatFactory {
|
||||
// *ending* index.
|
||||
for (RecipeElement el : recipe.getElements()) {
|
||||
// Do the prepend, and put "new" index at index 1
|
||||
mh = MethodHandles.dropArguments(mh, 2, int.class);
|
||||
switch (el.getTag()) {
|
||||
case TAG_CONST: {
|
||||
MethodHandle prepender = MethodHandles.insertArguments(prepender(String.class), 3, el.getValue());
|
||||
mh = MethodHandles.foldArguments(mh, 1, prepender,
|
||||
2, 0, 3 // index, storage, coder
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
|
||||
1, 0, 2 // index, storage, coder
|
||||
);
|
||||
break;
|
||||
}
|
||||
case TAG_ARG: {
|
||||
int pos = el.getArgPos();
|
||||
MethodHandle prepender = prepender(ptypes[pos]);
|
||||
mh = MethodHandles.foldArguments(mh, 1, prepender,
|
||||
2, 0, 3, // index, storage, coder
|
||||
4 + pos // selected argument
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
|
||||
1, 0, 2, // index, storage, coder
|
||||
3 + pos // selected argument
|
||||
);
|
||||
break;
|
||||
}
|
||||
@ -1557,7 +1556,7 @@ public final class StringConcatFactory {
|
||||
}
|
||||
|
||||
// Fold in byte[] instantiation at argument 0
|
||||
mh = MethodHandles.foldArguments(mh, 0, NEW_ARRAY,
|
||||
mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, NEW_ARRAY,
|
||||
1, 2 // index, coder
|
||||
);
|
||||
|
||||
@ -1572,7 +1571,7 @@ public final class StringConcatFactory {
|
||||
// and deduce the coder from there. Arguments would be either converted to Strings
|
||||
// during the initial filtering, or handled by primitive specializations in CODER_MIXERS.
|
||||
//
|
||||
// The method handle shape after all length and coder mixers is:
|
||||
// The method handle shape before and after all length and coder mixers is:
|
||||
// (int, byte, <args>)String = ("index", "coder", <args>)
|
||||
byte initialCoder = INITIAL_CODER;
|
||||
int initialLen = 0; // initial length, in characters
|
||||
@ -1589,44 +1588,27 @@ public final class StringConcatFactory {
|
||||
Class<?> argClass = ptypes[ac];
|
||||
MethodHandle lm = lengthMixer(argClass);
|
||||
|
||||
// Read these bottom up:
|
||||
|
||||
if (argClass.isPrimitive() && argClass != char.class) {
|
||||
|
||||
// 3. Drop old index, producing ("new-index", "coder", <args>)
|
||||
mh = MethodHandles.dropArguments(mh, 1, int.class);
|
||||
|
||||
// 2. Compute "new-index", producing ("new-index", "old-index", "coder", <args>)
|
||||
// Length mixer needs old index, plus the appropriate argument
|
||||
mh = MethodHandles.foldArguments(mh, 0, lm,
|
||||
1, // old-index
|
||||
3 + ac // selected argument
|
||||
// Compute new "index" in-place using old value plus the appropriate argument.
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, lm,
|
||||
0, // old-index
|
||||
2 + ac // selected argument
|
||||
);
|
||||
|
||||
// 1. The mh shape here is ("old-index", "coder", <args>); we don't need to recalculate
|
||||
// the coder for non-char primitive arguments
|
||||
|
||||
} else {
|
||||
MethodHandle cm = coderMixer(argClass);
|
||||
|
||||
// 4. Drop old index and coder, producing ("new-index", "new-coder", <args>)
|
||||
mh = MethodHandles.dropArguments(mh, 2, int.class, byte.class);
|
||||
|
||||
// 3. Compute "new-index", producing ("new-index", "new-coder", "old-index", "old-coder", <args>)
|
||||
// Length mixer needs old index, plus the appropriate argument
|
||||
mh = MethodHandles.foldArguments(mh, 0, lm,
|
||||
2, // old-index
|
||||
4 + ac // selected argument
|
||||
// Compute new "index" in-place using old value plus the appropriate argument.
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, lm,
|
||||
0, // old-index
|
||||
2 + ac // selected argument
|
||||
);
|
||||
|
||||
// 2. Compute "new-coder", producing ("new-coder", "old-index", "old-coder", <args>)
|
||||
// Coder mixer needs old coder, plus the appropriate argument.
|
||||
mh = MethodHandles.foldArguments(mh, 0, cm,
|
||||
2, // old-coder
|
||||
3 + ac // selected argument
|
||||
// Compute new "coder" in-place using old value plus the appropriate argument.
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, cm,
|
||||
1, // old-coder
|
||||
2 + ac // selected argument
|
||||
);
|
||||
|
||||
// 1. The mh shape here is ("old-index", "old-coder", <args>)
|
||||
}
|
||||
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user