JDK-8162815 : unnecessary object creation in reflection
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 9
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2016-07-31
  • Updated: 2019-08-26
  • Resolved: 2016-08-09
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 b131Fixed
Related Reports
Relates :  
Relates :  
Description
The fix for issue JDK-5043030 is incorrect. The generated code for reflection still allocates objects. It even makes the situation worse in cases when primitive wrapper classes' valueOf() allocates new instance. In such case the code allocates two objects. The fix for JDK-5043030 replaced invocation of constructor method with invocation of valueOf(), but it failed to remove actual object allocation. Take a look at the current bytecode of 'invoke' method below:

{
  public java.lang.Object invoke(java.lang.Object, java.lang.Object[]) throws java.lang.reflect.InvocationTargetException;
    descriptor: (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
    flags: ACC_PUBLIC
    Code:
      stack=7, locals=3, args_size=3
         0: new           #99                 // class java/lang/Long
         3: dup
         4: aload_1
         5: ifnonnull     16
         8: new           #18                 // class java/lang/NullPointerException
        11: dup
        12: invokespecial #26                 // Method java/lang/NullPointerException."<init>":()V
        15: athrow
        16: aload_1
        17: checkcast     #6                  // class java/lang/management/ThreadInfo
        20: aload_2
        21: ifnull        40
        24: aload_2
        25: arraylength
        26: sipush        0
        29: if_icmpeq     40
        32: new           #20                 // class java/lang/IllegalArgumentException
        35: dup
        36: invokespecial #27                 // Method java/lang/IllegalArgumentException."<init>":()V
        39: athrow
        40: invokevirtual #10                 // Method java/lang/management/ThreadInfo.getBlockedCount:()J
        43: invokestatic  #102                // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
        46: areturn
        47: invokespecial #40                 // Method java/lang/Object.toString:()Ljava/lang/String;
        50: new           #20                 // class java/lang/IllegalArgumentException
        53: dup_x1
        54: swap
        55: invokespecial #30                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
        58: athrow
        59: new           #22                 // class java/lang/reflect/InvocationTargetException
        62: dup_x1
        63: swap
        64: invokespecial #33                 // Method java/lang/reflect/InvocationTargetException."<init>":(Ljava/lang/Throwable;)V
        67: athrow
      Exception table:
         from    to  target type
            16    40    47   Class java/lang/ClassCastException
            16    40    47   Class java/lang/NullPointerException
            40    43    59   Class java/lang/Throwable
    Exceptions:
      throws java.lang.reflect.InvocationTargetException


The first bytecode instruction allocates instance of java.lang.Long, which is not used and return value of java.lang.Long.valueOf() is used (at offset 43).

Comments
Fix provided by Tom���� appears correct: the original code had a new+dup bytecode at the start of the method to prepare for a call to the constructor at the end. Since constructor call has been replaced with valueOf this should be removed. Performance characteristics indicate this does affect performance adversely in C1 (~10%), while C2 appears to be able to optimize away the (uninitialized) instantiation, but this can just as well be considered a correctness issue.
04-08-2016

The fix seems to be quite straightforward - just remove object allocation. See attached patch.
31-07-2016