8245969: Simplify String concat constant folding

Reviewed-by: psandoz, forax
This commit is contained in:
Claes Redestad 2020-05-28 00:35:04 +02:00
parent 69f7f95b93
commit 7e85b2c787
2 changed files with 78 additions and 72 deletions

View file

@ -190,11 +190,9 @@ final class StringConcatHelper {
* @param buf buffer to append to * @param buf buffer to append to
* @param value boolean value to encode * @param value boolean value to encode
* @param prefix a constant to prepend before value * @param prefix a constant to prepend before value
* @param suffix a constant to prepend after value
* @return updated index (coder value retained) * @return updated index (coder value retained)
*/ */
static long prepend(long indexCoder, byte[] buf, boolean value, String prefix, String suffix) { static long prepend(long indexCoder, byte[] buf, boolean value, String prefix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value); indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder; return indexCoder;
@ -209,11 +207,9 @@ final class StringConcatHelper {
* @param buf buffer to append to * @param buf buffer to append to
* @param value boolean value to encode * @param value boolean value to encode
* @param prefix a constant to prepend before value * @param prefix a constant to prepend before value
* @param suffix a constant to prepend after value
* @return updated index (coder value retained) * @return updated index (coder value retained)
*/ */
static long prepend(long indexCoder, byte[] buf, byte value, String prefix, String suffix) { static long prepend(long indexCoder, byte[] buf, byte value, String prefix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, (int)value); indexCoder = prepend(indexCoder, buf, (int)value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder; return indexCoder;
@ -247,11 +243,9 @@ final class StringConcatHelper {
* @param buf buffer to append to * @param buf buffer to append to
* @param value boolean value to encode * @param value boolean value to encode
* @param prefix a constant to prepend before value * @param prefix a constant to prepend before value
* @param suffix a constant to prepend after value
* @return updated index (coder value retained) * @return updated index (coder value retained)
*/ */
static long prepend(long indexCoder, byte[] buf, char value, String prefix, String suffix) { static long prepend(long indexCoder, byte[] buf, char value, String prefix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value); indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder; return indexCoder;
@ -266,11 +260,9 @@ final class StringConcatHelper {
* @param buf buffer to append to * @param buf buffer to append to
* @param value boolean value to encode * @param value boolean value to encode
* @param prefix a constant to prepend before value * @param prefix a constant to prepend before value
* @param suffix a constant to prepend after value
* @return updated index (coder value retained) * @return updated index (coder value retained)
*/ */
static long prepend(long indexCoder, byte[] buf, short value, String prefix, String suffix) { static long prepend(long indexCoder, byte[] buf, short value, String prefix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, (int)value); indexCoder = prepend(indexCoder, buf, (int)value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder; return indexCoder;
@ -303,11 +295,9 @@ final class StringConcatHelper {
* @param buf buffer to append to * @param buf buffer to append to
* @param value boolean value to encode * @param value boolean value to encode
* @param prefix a constant to prepend before value * @param prefix a constant to prepend before value
* @param suffix a constant to prepend after value
* @return updated index (coder value retained) * @return updated index (coder value retained)
*/ */
static long prepend(long indexCoder, byte[] buf, int value, String prefix, String suffix) { static long prepend(long indexCoder, byte[] buf, int value, String prefix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value); indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder; return indexCoder;
@ -340,11 +330,9 @@ final class StringConcatHelper {
* @param buf buffer to append to * @param buf buffer to append to
* @param value boolean value to encode * @param value boolean value to encode
* @param prefix a constant to prepend before value * @param prefix a constant to prepend before value
* @param suffix a constant to prepend after value
* @return updated index (coder value retained) * @return updated index (coder value retained)
*/ */
static long prepend(long indexCoder, byte[] buf, long value, String prefix, String suffix) { static long prepend(long indexCoder, byte[] buf, long value, String prefix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value); indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder; return indexCoder;
@ -379,11 +367,9 @@ final class StringConcatHelper {
* @param buf buffer to append to * @param buf buffer to append to
* @param value boolean value to encode * @param value boolean value to encode
* @param prefix a constant to prepend before value * @param prefix a constant to prepend before value
* @param suffix a constant to prepend after value
* @return updated index (coder value retained) * @return updated index (coder value retained)
*/ */
static long prepend(long indexCoder, byte[] buf, String value, String prefix, String suffix) { static long prepend(long indexCoder, byte[] buf, String value, String prefix) {
if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
indexCoder = prepend(indexCoder, buf, value); indexCoder = prepend(indexCoder, buf, value);
if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
return indexCoder; return indexCoder;
@ -422,8 +408,8 @@ final class StringConcatHelper {
String s2 = stringOf(second); String s2 = stringOf(second);
// start "mixing" in length and coder or arguments, order is not // start "mixing" in length and coder or arguments, order is not
// important // important
long indexCoder = mix(initialCoder(), s2); long indexCoder = mix(initialCoder(), s1);
indexCoder = mix(indexCoder, s1); indexCoder = mix(indexCoder, s2);
byte[] buf = newArray(indexCoder); byte[] buf = newArray(indexCoder);
// prepend each argument in reverse order, since we prepending // prepend each argument in reverse order, since we prepending
// from the end of the byte array // from the end of the byte array
@ -449,6 +435,28 @@ final class StringConcatHelper {
private static final Unsafe UNSAFE = Unsafe.getUnsafe(); private static final Unsafe UNSAFE = Unsafe.getUnsafe();
/**
* Allocates an uninitialized byte array based on the length and coder
* information, then prepends the given suffix string at the end of the
* byte array before returning it. The calling code must adjust the
* indexCoder so that it's taken the coder of the suffix into account, but
* subtracted the length of the suffix.
*
* @param suffix
* @param indexCoder
* @return the newly allocated byte array
*/
@ForceInline
static byte[] newArrayWithSuffix(String suffix, long indexCoder) {
byte[] buf = newArray(indexCoder + suffix.length());
if (indexCoder < UTF16) {
suffix.getBytes(buf, (int)indexCoder, String.LATIN1);
} else {
suffix.getBytes(buf, (int)indexCoder, String.UTF16);
}
return buf;
}
/** /**
* Allocates an uninitialized byte array based on the length and coder information * Allocates an uninitialized byte array based on the length and coder information
* in indexCoder * in indexCoder
@ -478,5 +486,4 @@ final class StringConcatHelper {
} }
} }
} }

View file

@ -615,8 +615,7 @@ public final class StringConcatFactory {
// We need one prepender per argument, but also need to fold in constants. We do so by greedily // We need one prepender per argument, but also need to fold in constants. We do so by greedily
// create prependers that fold in surrounding constants into the argument prepender. This reduces // create prependers that fold in surrounding constants into the argument prepender. This reduces
// the number of unique MH combinator tree shapes we'll create in an application. // the number of unique MH combinator tree shapes we'll create in an application.
String prefixConstant = null, suffixConstant = null; String constant = null;
int pos = -1;
for (RecipeElement el : recipe.getElements()) { for (RecipeElement el : recipe.getElements()) {
// Do the prepend, and put "new" index at index 1 // Do the prepend, and put "new" index at index 1
switch (el.getTag()) { switch (el.getTag()) {
@ -626,29 +625,22 @@ public final class StringConcatFactory {
// Eagerly update the initialLengthCoder value // Eagerly update the initialLengthCoder value
initialLengthCoder = JLA.stringConcatMix(initialLengthCoder, constantValue); initialLengthCoder = JLA.stringConcatMix(initialLengthCoder, constantValue);
if (pos < 0) { // Collecting into a single constant that we'll either fold
// Collecting into prefixConstant // into the next argument prepender, or into the newArray
prefixConstant = prefixConstant == null ? constantValue : prefixConstant + constantValue; // combinator
} else { constant = constant == null ? constantValue : constant + constantValue;
// Collecting into suffixConstant
suffixConstant = suffixConstant == null ? constantValue : suffixConstant + constantValue;
}
break; break;
} }
case TAG_ARG: { case TAG_ARG: {
// Add prepender, along with any prefix constant
if (pos >= 0) { int pos = el.getArgPos();
// Flush the previous non-constant arg with any prefix/suffix constant mh = MethodHandles.filterArgumentsWithCombiner(
mh = MethodHandles.filterArgumentsWithCombiner( mh, 1,
mh, 1, prepender(constant, ptypes[pos]),
prepender(prefixConstant, ptypes[pos], suffixConstant), 1, 0, // indexCoder, storage
1, 0, // indexCoder, storage 2 + pos // selected argument
2 + pos // selected argument );
); constant = null;
prefixConstant = suffixConstant = null;
}
// Mark the pos of next non-constant arg
pos = el.getArgPos();
break; break;
} }
default: default:
@ -656,26 +648,22 @@ public final class StringConcatFactory {
} }
} }
// Insert any trailing args, constants
if (pos >= 0) {
mh = MethodHandles.filterArgumentsWithCombiner(
mh, 1,
prepender(prefixConstant, ptypes[pos], suffixConstant),
1, 0, // indexCoder, storage
2 + pos // selected argument
);
} else if (prefixConstant != null) {
assert (suffixConstant == null);
// Sole prefixConstant can only happen if there were no non-constant arguments
mh = MethodHandles.filterArgumentsWithCombiner(
mh, 1,
MethodHandles.insertArguments(prepender(null, String.class, null), 2, prefixConstant),
1, 0 // indexCoder, storage
);
}
// Fold in byte[] instantiation at argument 0 // Fold in byte[] instantiation at argument 0
mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, newArray(), MethodHandle newArrayCombinator;
if (constant != null) {
// newArray variant that deals with prepending the trailing constant
//
// initialLengthCoder has been adjusted to have the correct coder
// and length already, but to avoid binding an extra variable to
// the method handle we now adjust the length to be correct for the
// first prepender above, while adjusting for the missing length of
// the constant in StringConcatHelper
initialLengthCoder -= constant.length();
newArrayCombinator = newArrayWithSuffix(constant);
} else {
newArrayCombinator = newArray();
}
mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, newArrayCombinator,
1 // index 1 // index
); );
@ -746,25 +734,25 @@ public final class StringConcatFactory {
return mh; return mh;
} }
private static MethodHandle prepender(String prefix, Class<?> cl, String suffix) { private static MethodHandle prepender(String prefix, Class<?> cl) {
if (prefix == null && suffix == null) { if (prefix == null) {
return NULL_PREPENDERS.computeIfAbsent(cl, NULL_PREPEND); return NULL_PREPENDERS.computeIfAbsent(cl, NULL_PREPEND);
} }
return MethodHandles.insertArguments( return MethodHandles.insertArguments(
PREPENDERS.computeIfAbsent(cl, PREPEND), 3, prefix, suffix); PREPENDERS.computeIfAbsent(cl, PREPEND), 3, prefix);
} }
private static MethodHandle mixer(Class<?> cl) { private static MethodHandle mixer(Class<?> cl) {
return MIXERS.computeIfAbsent(cl, MIX); return MIXERS.computeIfAbsent(cl, MIX);
} }
// This one is deliberately non-lambdified to optimize startup time: // These are deliberately not lambdas to optimize startup time:
private static final Function<Class<?>, MethodHandle> PREPEND = new Function<>() { private static final Function<Class<?>, MethodHandle> PREPEND = new Function<>() {
@Override @Override
public MethodHandle apply(Class<?> c) { public MethodHandle apply(Class<?> c) {
return JLA.stringConcatHelper("prepend", return JLA.stringConcatHelper("prepend",
methodType(long.class, long.class, byte[].class, methodType(long.class, long.class, byte[].class,
Wrapper.asPrimitiveType(c), String.class, String.class)); Wrapper.asPrimitiveType(c), String.class));
} }
}; };
@ -772,11 +760,10 @@ public final class StringConcatFactory {
@Override @Override
public MethodHandle apply(Class<?> c) { public MethodHandle apply(Class<?> c) {
return MethodHandles.insertArguments( return MethodHandles.insertArguments(
PREPENDERS.computeIfAbsent(c, PREPEND), 3, (String)null, (String)null); PREPENDERS.computeIfAbsent(c, PREPEND), 3, (String)null);
} }
}; };
// This one is deliberately non-lambdified to optimize startup time:
private static final Function<Class<?>, MethodHandle> MIX = new Function<>() { private static final Function<Class<?>, MethodHandle> MIX = new Function<>() {
@Override @Override
public MethodHandle apply(Class<?> c) { public MethodHandle apply(Class<?> c) {
@ -801,6 +788,18 @@ public final class StringConcatFactory {
} }
return mh; return mh;
} }
private @Stable static MethodHandle NEW_ARRAY_SUFFIX;
private static MethodHandle newArrayWithSuffix(String suffix) {
MethodHandle mh = NEW_ARRAY_SUFFIX;
if (mh == null) {
NEW_ARRAY_SUFFIX = mh =
JLA.stringConcatHelper("newArrayWithSuffix",
methodType(byte[].class, String.class, long.class));
}
return MethodHandles.insertArguments(mh, 0, suffix);
}
private @Stable static MethodHandle NEW_ARRAY; private @Stable static MethodHandle NEW_ARRAY;
private static MethodHandle newArray() { private static MethodHandle newArray() {
MethodHandle mh = NEW_ARRAY; MethodHandle mh = NEW_ARRAY;