mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8245969: Simplify String concat constant folding
Reviewed-by: psandoz, forax
This commit is contained in:
parent
69f7f95b93
commit
7e85b2c787
2 changed files with 78 additions and 72 deletions
|
@ -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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue