- Loading...
| Table of Contents |
|---|
Improve start-up time by storing pre-generated LambdaForm handlers in an application-specific CDS archive.
In JDK-8086045 (Improve the java.lang.invoke first initialization costs), the JDK can reduce the number of dynamically generated LambdaForm LambdaForm classes. Here's an example:
| No Format |
|---|
# Do this in your JDK build directory.
# The exploded JDK build:
$ jdk/bin/javac -J-verbose ~/tmp/HelloWorld.java | grep LambdaForm | grep __JVM_LookupDefineClass__
[0.142s][info][class,load] java.lang.invoke.LambdaForm$MH/0x0000000800066c40 source: __JVM_LookupDefineClass__
[0.143s][info][class,load] java.lang.invoke.LambdaForm$DMH/0x0000000800066040 source: __JVM_LookupDefineClass__
[0.143s][info][class,load] java.lang.invoke.LambdaForm$MH/0x0000000800066440 source: __JVM_LookupDefineClass__
[snip]
$ jdk/bin/javac -J-verbose ~/tmp/HelloWorld.java | grep LambdaForm | grep __JVM_LookupDefineClass__ | wc
102 408 11400
# The final JDK image:
$ images/jdk/bin/javac -J-verbose ~/tmp/HelloWorld.java | grep LambdaForm | grep __JVM_LookupDefineClass__ | wc
34 136 3800 |
...
The input of generateDirectMethodHandleHolderClassBytes comes from the defaultthe default_jli_trace.txt file that is generated in GenerateLinkOptData.gmk:
...
| Code Block |
|---|
$ grep invokeSpecialIFC ./support/link_opt/default_jli_trace.txt [LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeSpecialIFC L3I_I (fail) [LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeSpecialIFC LLI_I (fail) $ images/jdk/bin/javap 'java.lang.invoke.DirectMethodHandle$Holder' | grep invokeSpecialIFC static int invokeSpecialIFC(java.lang.Object, java.lang.Object, java.lang.Object, int); static int invokeSpecialIFC(java.lang.Object, java.lang.Object, int); |
The methods in DirectMethodHandle$Holder in DirectMethodHandle$Holder are used in InvokerBytecodeGenerator.java when compiling for LambdaForms:
| Code Block |
|---|
private static MemberName lookupPregenerated(LambdaForm form, MethodType invokerType) {
if (form.customized != null) {
// No pre-generated version for customized LF
return null;
}
String name = form.kind.methodName;
switch (form.kind) {
[......]
case DIRECT_INVOKE_INTERFACE: // fall-through
case DIRECT_INVOKE_SPECIAL: // fall-through
case DIRECT_INVOKE_SPECIAL_IFC: // fall-through
case DIRECT_INVOKE_STATIC: // fall-through
case DIRECT_INVOKE_STATIC_INIT: // fall-through
case DIRECT_INVOKE_VIRTUAL: return resolveFrom(name, invokerType, DirectMethodHandle.Holder.class);
}
return null; |
The expected benefits will be application specific. Here's an experiment with Javac (I modified the JDK makefile to invoke com.sun.tools.javac.Main while generating default_jli_trace.txt).
| Code Block |
|---|
Results of " perf stat -r 50 bin/javac -J-Xshare:on -J-XX:SharedArchiveFile=javac2.jsa Bench_HelloWorld.java "
1: 2239149872 2203293903 (-35855969) ---- 375.580 367.190 ( -8.390) ----
2: 2245304165 2198900711 (-46403454) ----- 375.350 366.910 ( -8.440) ----
3: 2242558895 2205167765 (-37391130) ---- 376.720 366.480 (-10.240) -----
4: 2246851428 2198990987 (-47860441) ----- 375.119 367.010 ( -8.109) ----
5: 2238549008 2202480450 (-36068558) ---- 374.100 367.600 ( -6.500) ---
6: 2240816859 2200725384 (-40091475) ---- 375.743 366.880 ( -8.863) ----
7: 2243272464 2199639926 (-43632538) ----- 374.296 365.990 ( -8.306) ----
8: 2239650882 2203211291 (-36439591) ---- 375.315 365.520 ( -9.795) -----
9: 2242434935 2202380291 (-40054644) ---- 376.052 367.305 ( -8.747) ----
10: 2238725993 2201342398 (-37383595) ---- 375.478 366.743 ( -8.735) ----
============================================================
2241729810 2201612439 (-40117371) ---- 375.375 366.762 ( -8.612) ----
instr delta = -40117371 -1.7896%
time delta = -8.612 ms -2.2943% |
Overally, we want to modify lookupPregenerated() to something like:
| Code Block |
|---|
case xxxxxx: return resolveFrom(name, invokerType, directMethodHandleHolders);
Class[] directMethodHandleHolders = {
DirectMethodHandle.Holder.class, // the one in jdk/lib/modules
Class.forName("java/lang/invoke/DirectMethodHandle$CDSHolder1"), // if available, from CDS static archive
Class.forName("java/lang/invoke/DirectMethodHandle$CDSHolder2"), // if available, from CDS static archive
}; |
During CDS dump (static or dynamic), we will generate the CDSHolder1 and CDSHolder2 classes according to the program's execution profile.
We regenerate the XXX$Holder classes to contain all necessary methods used by the application.
This has been implemented in JDK-8247536 (Support for pre-generated java.lang.invoke classes in CDS static archive - integrated into JDK 16).
During the trial run (with -XX:DumpLoadedClassList=classlist), we can save the list of LambdaForm handlers using a special syntax like:
| Code Block |
|---|
# regular class specifier java/lang/Object # LambdaForm specifier (syntax TBD, but probably following the output of # -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true @lambda-form-invoker [LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeSpecialIFC L3I_I [LF@lambda-form-invoker [SPECIES_RESOLVE] java.lang.invoke.SimpleMethodHandle |
We collect all the @lambda-form-invoker lines when parsing the classlist. At the end of the static dump:
...
Preliminary webrev:
...