JDK-8129547 : Excess entries in BootstrapMethods with the same (bsm, bsmKind, bsmStaticArgs), but different dynamicArgs
  • Type: Enhancement
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 9
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2015-06-23
  • Updated: 2015-09-10
  • Resolved: 2015-08-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b80Fixed
Related Reports
Relates :  
Relates :  
Description
This was found during the work on indify String concat (JDK-8085796).

In short, when javac is asked to produce an indy method call, it accumulates the bootstrap methods in the map below:

    /** The bootstrap methods to be written in the corresponding class attribute
     *  (one for each invokedynamic)
     */
    Map<DynamicMethod, MethodHandle> bootstrapMethods;

DynamicMethod's equals treats dynamic arguments for the call as key (through Method.equals() supercall), which makes javac to emit duplicate entries in BootstrapMethods, while a common entry is sometimes enough. For example, different "shapes" of dynamic arguments all call into the same bootstrap method with the same static args, but each indy produces its own BSM entry:

       600: invokedynamic #202,  0            // InvokeDynamic #0:stringConcat:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;...;Ljava/lang/String;)Ljava/lang/String;
       ...
      30253: invokedynamic #10004,  0         // InvokeDynamic #1:stringConcat:(Ljava/lang/String;)Ljava/lang/String;
       ...
      30258: invokedynamic #10005,  0         // InvokeDynamic #2:stringConcat:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;...;Ljava/lang/String;)Ljava/lang/String;

BootstrapMethods:
  0: #10120 invokestatic java/lang/invoke/StringConcatFactory.stringConcat:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
  1: #10120 invokestatic java/lang/invoke/StringConcatFactory.stringConcat:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
  2: #10120 invokestatic java/lang/invoke/StringConcatFactory.stringConcat:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:

After the proof-of-concept patch:
  http://cr.openjdk.java.net/~shade/8129547/webrev.00/

       600: invokedynamic #202,  0            // InvokeDynamic #0:stringConcat:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;...;Ljava/lang/String;)Ljava/lang/String;
        ...
      30253: invokedynamic #10004,  0         // InvokeDynamic #0:stringConcat:(Ljava/lang/String;)Ljava/lang/String;
        ...
      30258: invokedynamic #10005,  0         // InvokeDynamic #0:stringConcat:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;...;Ljava/lang/String;)Ljava/lang/String;

BootstrapMethods:
  0: #10120 invokestatic java/lang/invoke/StringConcatFactory.stringConcat:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:

For indify String concat project, this improves the bytecode footprint from 100.000.006 bytes to 99.998.563 bytes (-1443 bytes) when the entire JDK is compiled.