Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8327695

[lworld] javac can generate incorrect code in inner class' constructors

XMLWordPrintable

      Test test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java fails with the following output:

      Error Output
      ------------
      Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
      Exception Details:
        Location:
          compiler/valhalla/inlinetypes/TestBasicFunctionality$Test37Value1.<init>(Lcompiler/valhalla/inlinetypes/TestBasicFunctionality;)V @21: getfield
        Reason:
          Type uninitializedThis (current frame, stack[3]) is not assignable to 'compiler/valhalla/inlinetypes/TestBasicFunctionality$Test37Value1'
        Current Frame:
          bci: @21
          flags: { flagThisUninit }
          locals: { uninitializedThis, 'compiler/valhalla/inlinetypes/TestBasicFunctionality' }
          stack: { uninitializedThis, uninitialized 16, uninitialized 16, uninitializedThis }
        Bytecode:
          0000000: 2a2b b500 012a 0eb5 0007 2a0b b500 0b2a
          0000010: bb00 0f59 2ab4 0001 b700 11b5 0015 2ab7
          0000020: 0019 b1

      at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
      at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3665)
      at java.base/java.lang.Class.getDeclaredMethods(Class.java:2765)
      at compiler.lib.ir_framework.test.TestVM.checkAnnotationsInClass(TestVM.java:221)
      at compiler.lib.ir_framework.test.TestVM.setupTests(TestVM.java:257)
      at compiler.lib.ir_framework.test.TestVM.start(TestVM.java:248)
      at compiler.lib.ir_framework.test.TestVM.main(TestVM.java:165)

      Apparently, this is due to a compilation error from javac.
      When decompiling TestBasicFunctionality$Test37Value1, here’s the code of the constructor:
        compiler.valhalla.inlinetypes.TestBasicFunctionality$Test37Value1(compiler.valhalla.inlinetypes.TestBasicFunctionality);
          descriptor: (Lcompiler/valhalla/inlinetypes/TestBasicFunctionality;)V
          flags: (0x0000)
          Code:
            stack=4, locals=2, args_size=2
               0: aload_0
               1: aload_1
               2: putfield #1 // Field this$0:Lcompiler/valhalla/inlinetypes/TestBasicFunctionality;
               5: aload_0
               6: dconst_0
               7: putfield #7 // Field d:D
              10: aload_0
              11: fconst_0
              12: putfield #11 // Field f:F
              15: aload_0
              16: new #15 // class compiler/valhalla/inlinetypes/TestBasicFunctionality$Test37Value2
              19: dup
              20: aload_0
              21: getfield #1 // Field this$0:Lcompiler/valhalla/inlinetypes/TestBasicFunctionality;
              24: invokespecial #17 // Method compiler/valhalla/inlinetypes/TestBasicFunctionality$Test37Value2."<init>":(Lcompiler/valhalla/inlinetypes/TestBasicFunctionali
      ty;)V
              27: putfield #21 // Field v:Lcompiler/valhalla/inlinetypes/TestBasicFunctionality$Test37Value2;
              30: aload_0
              31: invokespecial #25 // Method java/lang/Object."<init>":()V
              34: return
            LineNumberTable:
              line 887: 0
              line 888: 5
              line 889: 10
              line 890: 15
              line 887: 30
          MethodParameters:
            Name Flags
            <no name> final mandated


      The problem is with the handling of the this$0 field, which is an artifact used by javac to store in an instance of an inner class, a reference to the outer class or instance.
      The value of this$0 is passed in argument to the constructor, and javac generates code to store it to the this$0 field, good.
      However, later in the constructor, javac needs this value to invoke the constructor of another inner class, and it tries to get it by reading it from the this$0 field, which is illegal because the super’s constructor hasn’t been called yet.
      Instead, javac should reuse the argument (still stored in local variable 1) instead of trying to read the field (this change would require javac to ensure that the argument is preserved in the local variable).

            vromero Vicente Arturo Romero Zaldivar
            fparain Frederic Parain
            Votes:
            1 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: