-
Bug
-
Resolution: Fixed
-
P3
-
repo-valhalla
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).
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).