RFR: 8336856: Optimize String Concat [v39]
Shaojin Wen
duke at openjdk.org
Fri Aug 9 05:58:40 UTC 2024
On Thu, 8 Aug 2024 11:43:07 GMT, Shaojin Wen <duke at openjdk.org> wrote:
>> This PR implements the same algorithm as the current generateMHInlineCopy based on bytecode to improve startup performance.
>
> Shaojin Wen has updated the pull request incrementally with one additional commit since the last revision:
>
> fix comments
I've found a way to verify that unloading of the hidden concat classes works.
Run the following code:
import java.lang.invoke.*;
public class HiddenClassUnloading {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class<?>[] types = new Class[] {
int.class, long.class, double.class, float.class, char.class, boolean.class, String.class,
};
Object[] values = new Object[] {
1, 1L, 1D, 1F, 'C', true, "A",
};
int sum = 0;
for (int i = 0; i < 1_000_000; i++) {
int radix = types.length;
String str = Integer.toString(i, radix);
int length = str.length();
String recipe = "\1".repeat(length);
Class<?>[] ptypes = new Class[length];
Object[] pvalues = new Object[length];
for (int j = 0; j < length; j++) {
int index = Integer.parseInt(str.substring(j, j + 1), radix);
ptypes[j] = types[index];
pvalues[j] = values[index];
}
MethodType concatType = MethodType.methodType(String.class, ptypes);
CallSite callSite = StringConcatFactory.makeConcatWithConstants(
lookup,
"concat",
concatType,
recipe,
new Object[0]
);
MethodHandle mh = callSite.dynamicInvoker();
String result = switch (length) {
case 1 -> (String) mh.invoke(pvalues[0]);
case 2 -> (String) mh.invoke(pvalues[0], pvalues[1]);
case 3 -> (String) mh.invoke(pvalues[0], pvalues[1], pvalues[2]);
case 4 -> (String) mh.invoke(pvalues[0], pvalues[1], pvalues[2], pvalues[3]);
case 5 -> (String) mh.invoke(pvalues[0], pvalues[1], pvalues[2], pvalues[3], pvalues[4]);
case 6 -> (String) mh.invoke(pvalues[0], pvalues[1], pvalues[2], pvalues[3], pvalues[4], pvalues[5]);
case 7 -> (String) mh.invoke(pvalues[0], pvalues[1], pvalues[2], pvalues[3], pvalues[4], pvalues[5], pvalues[6]);
case 8 -> (String) mh.invoke(pvalues[0], pvalues[1], pvalues[2], pvalues[3], pvalues[4], pvalues[5], pvalues[6], pvalues[7]);
case 9 -> (String) mh.invoke(pvalues[0], pvalues[1], pvalues[2], pvalues[3], pvalues[4], pvalues[5], pvalues[6], pvalues[7], pvalues[8]);
case 10 -> (String) mh.invoke(pvalues[0], pvalues[1], pvalues[2], pvalues[3], pvalues[4], pvalues[5], pvalues[6], pvalues[7], pvalues[8], pvalues[9]);
default -> throw new RuntimeException("length too large " + length);
};
sum += result.length();
}
System.out.println(sum);
}
}
We use jmap -histo to observe whether the number of hidden classes is growing continuously.
# get pid
jps | grep HiddenClassUnloading
# Count the number of hidden classes
jmap -histo <pid> | grep -c "StringConcat/0"
The result is as follows, the number of hidden classes does not keep growing, so the unloading of hidden classes is working.
➜ jmap -histo 1037 | grep -c "StringConcat/0"
17
➜ jmap -histo 1037 | grep -c "StringConcat/0"
43
➜ jmap -histo 1037 | grep -c "StringConcat/0"
77
➜ jmap -histo 1037 | grep -c "StringConcat/0"
92
➜ jmap -histo 1037 | grep -c "StringConcat/0"
110
➜ jmap -histo 1037 | grep -c "StringConcat/0"
133
➜ jmap -histo 1037 | grep -c "StringConcat/0"
159
➜ jmap -histo 1037 | grep -c "StringConcat/0"
2
➜ jmap -histo 1037 | grep -c "StringConcat/0"
-------------
PR Comment: https://git.openjdk.org/jdk/pull/20273#issuecomment-2277202933
More information about the core-libs-dev
mailing list