On Thu, 8 Aug 2024 11:43:07 GMT, Shaojin Wen <d...@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