RFR: 8292914: Introduce a system property that enables stable names for lambda proxy classes

Strahinja Stanojevic duke at openjdk.org
Tue Oct 18 07:48:04 UTC 2022


On Tue, 6 Sep 2022 16:47:03 GMT, Ioi Lam <iklam at openjdk.org> wrote:

>> This PR introduces a system property that creates stable names for the lambda classes in the JDK. Instead of using an atomic counter in the lambda name, we can use a 32-bit hash after `$$Lambda$`. Thus, the name becomes `lambdaCapturingClass$$Lambda$hashValue`.
>> Parameters used to create a stable part of the name (hash value) are a superset of the parameters used for lambda class archiving when the CDS dumping option is enabled. During the stable name creation process,
>> all the common parameters are in the same form as in the low-level implementation (C part of the code) of the archiving process.
>> We concatenate all of those parameters in one string `hashData`. We calculate the long hash value for `hashData` in the same manner as the `java.lang.StringUTF16#hashCode` does, and then we hash that value using `Long.toString(longHashValue, Character.MAX_RADIX)`. The desired length for this hash is equal to the length of the `Long.toString(Long.MAX_VALUE, Character.MAX_RADIX)`.
>> Sometimes, the calculated hash value is shorter than the desired length, so we pad it with the character `#` to hit it. Appending `#` only affects the hash length, but not its stability.
>> 
>> Link to the related issue: https://bugs.openjdk.org/browse/JDK-8292914
>
> Have you tested with method references? Two references to the same method will result in a single `JVM_CONSTANT_InvokeDynamic` constant pool entry in the classfile, but it's invoked by two callsites. As a result, two different lambda proxy classes will be generated, as the JVMS requires the invokedynamic resolution to be per callsite, not per constantpool entry.
> 
> 
> public class ShareBSM {
>   public static void main(String args[]) {
>     doit1(ShareBSM::func);
>     doit2(ShareBSM::func);
>   }
>   static void func() {  Thread.dumpStack();  }
>   static void doit1(Runnable r) {  r.run();  }
>   static void doit2(Runnable r) {  r.run();  }
> }
> 
> 
> Here's the output:
> 
> 
> $ java -cp . -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames ShareBSM
> java.lang.Exception: Stack trace
> 	at java.base/java.lang.Thread.dumpStack(Thread.java:1380)
> 	at ShareBSM.func(ShareBSM.java:8)
> 	at ShareBSM$$Lambda$1/0x0000000800c009f0.run(Unknown Source)
> 	at ShareBSM.doit1(ShareBSM.java:12)
> 	at ShareBSM.main(ShareBSM.java:3)
> java.lang.Exception: Stack trace
> 	at java.base/java.lang.Thread.dumpStack(Thread.java:1380)
> 	at ShareBSM.func(ShareBSM.java:8)
> 	at ShareBSM$$Lambda$2/0x0000000800c00bf8.run(Unknown Source)
> 	at ShareBSM.doit2(ShareBSM.java:15)
> 	at ShareBSM.main(ShareBSM.java:4)
> 
> 
> Will you patch generate the same name for both callsites? Does this matter for your use case?

Hi @iklam, is there any additional work I can do on this PR?

-------------

PR: https://git.openjdk.org/jdk/pull/10024


More information about the core-libs-dev mailing list