-
Bug
-
Resolution: Not an Issue
-
P3
-
None
-
11
-
x86_64
-
windows
ADDITIONAL SYSTEM INFORMATION :
ADDITIONAL SYSTEM INFORMATION :
OS:
Operating System Name: Windows 11
Operating System Architecture: amd64
Operating System Version: 10.0
OpenJDK version:
java version "11.0.26" 2025-01-21 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.26+7-LTS-187)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.26+7-LTS-187, mixed mode)
openjdk version "11.0.27" 2025-04-15
IBM Semeru Runtime Open Edition 11.0.27.0 (build 11.0.27+6)
Eclipse OpenJ9 VM 11.0.27.0 (build openj9-0.51.0, JRE 11 Windows 11 amd64-64-Bit Compressed References 20250504_1192 (JIT enabled, AOT enabled)
OpenJ9 - 31cf5538b0
OMR - 9bcff94a2
JCL - 3e17c0897e based on jdk-11.0.27+6)
A DESCRIPTION OF THE PROBLEM :
Given a test case, we found that the execution results of this test case on different JVMs are different, the simplified test case can be found below. In summary, Hotspot(11.0.26) threw IllegalAccessError while J9(11.0.27) threw AbstractMethodError.
REGRESSION : Last worked in version 11
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The following code can be used to generate the test cases(.class file) that reproduces the above process:
```java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class BytecodeUtil {
public static void main(String args[]) {
// create package
String baseDir = "./your_dir"; // your base dir
File P0 = new File(baseDir + "/" + "P0");
File P3 = new File(baseDir + "/" + "P3");
P0.mkdirs();
P3.mkdirs();
String P0_C2_bytecodeInStr = "CAFEBABE00000034001201000550302F433207000101000550332F43310700030100063C696E69743E0100032829560C000500060A000400070100016D01001528294C6A6176612F6C616E672F496E74656765723B0100116A6176612F6C616E672F496E746567657207000B0300000002010004284929560C0005000E0A000C000F010004436F6465002100020004000000000002000100050006000100110000001100010001000000052AB70008B10000000000020009000A0001001100000016000300010000000ABB000C59120DB70010B0000000000000" ;
String P0_helper_bytecodeInStr = "CAFEBABE00000034000F01000950302F48656C7065720700010100106A6176612F6C616E672F4F626A6563740700030100063C696E69743E0100032829560C000500060A00040007010005676574433201000928294C50302F43323B01000550302F433207000B0A000C0007010004436F64650021000200040000000000020001000500060001000E0000001100010001000000052AB70008B10000000000090009000A0001000E00000016000200010000000ABB000C59B7000D4B2AB0000000000000" ;
String P0_I0_bytecodeInStr = "CAFEBABE00000034002701000550302F49300700010100106A6176612F6C616E672F4F626A6563740700030100016D01001528294C6A6176612F6C616E672F496E74656765723B0100047465737401000950302F48656C706572070008010005676574433201000928294C50302F43323B0C000A000B0A0009000C0C000500060B0002000E0100046D61696E010016285B4C6A6176612F6C616E672F537472696E673B29560C000700060B000200120100106A6176612F6C616E672F53797374656D0700140100036F75740100154C6A6176612F696F2F5072696E7453747265616D3B0C00160017090015001801000E52657475726E2076616C75653A2008001A0100136A6176612F696F2F5072696E7453747265616D07001C0100057072696E74010015284C6A6176612F6C616E672F537472696E673B29560C001E001F0A001D00200100077072696E746C6E010015284C6A6176612F6C616E672F4F626A6563743B29560C002200230A001D0024010004436F646506010002000400000000000304010005000600000009000700060001002600000017000100010000000BB8000D4B2AB9000F0100B000000000000900100011000100260000001E0003000200000012B800134CB2001959121BB600212BB60025B1000000000000" ;
String P3_C1_bytecodeInStr = "CAFEBABE00000034001401000550332F43310700010100106A6176612F6C616E672F4F626A65637407000301000550302F49300700050100063C696E69743E0100032829560C000700080A000400090100016D01001528294C6A6176612F6C616E672F496E74656765723B0100116A6176612F6C616E672F496E746567657207000D0300000001010004284929560C000700100A000E0011010004436F64650021000200040001000600000002000100070008000100130000001100010001000000052AB7000AB1000000000000000B000C0001001300000016000300010000000ABB000E59120FB70012B0000000000000" ;
String P3_Helper_bytecodeInStr = "CAFEBABE00000034000F01000950332F48656C7065720700010100106A6176612F6C616E672F4F626A6563740700030100063C696E69743E0100032829560C000500060A00040007010005676574433101000928294C50332F43313B01000550332F433107000B0A000C0007010004436F64650021000200040000000000020001000500060001000E0000001100010001000000052AB70008B10000000000090009000A0001000E00000016000200010000000ABB000C59B7000D4B2AB0000000000000" ;
try (FileOutputStream fos = new FileOutputStream(P0.getAbsolutePath() + "/" + "C2.class")) {
byte[] P0_C2_bytecode = hexStringToByteArray(P0_C2_bytecodeInStr);
fos.write(P0_C2_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(P0.getAbsolutePath() + "/" + "Helper.class")) {
byte[] P0_helper_bytecode = hexStringToByteArray(P0_helper_bytecodeInStr);
fos.write(P0_helper_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(P0.getAbsolutePath() + "/" + "I0.class")) {
byte[] P0_I0_bytecode = hexStringToByteArray(P0_I0_bytecodeInStr);
fos.write(P0_I0_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(P3.getAbsolutePath() + "/" + "C1.class")) {
byte[] P3_C1_bytecode = hexStringToByteArray(P3_C1_bytecodeInStr);
fos.write(P3_C1_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(P3.getAbsolutePath() + "/" + "Helper.class")) {
byte[] P3_Helper_bytecode = hexStringToByteArray(P3_Helper_bytecodeInStr);
fos.write(P3_Helper_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
}
public static byte[] hexStringToByteArray(String hexString) {
int length = hexString.length();
byte[] byteArray = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
int byteValue = Integer.parseInt(hexString.substring(i, i + 2), 16);
byteArray[i / 2] = (byte) byteValue;
}
return byteArray;
}
}
```
Note: modify the paths according to your needs.
Repoduce:
>>> path_to_jdk/Hotspot_11.0.26/bin/java -cp . P0.I0
>>> path_to_jdk/openj9/11.0.27/bin/java -cp . P0.I0
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
According to this interesting result, we first decompiled P0.I0 using javap. The results are as follows:
```java
Classfile /D:/Lab/TestJDoc/reduce/Test_JDoc/log/jvm-test/openj9-8/InterfaceSignatureConflictTest/case_21/P0/I0.class
Last modified Jul 3, 2025; size 478 bytes
MD5 checksum f92264b361e06d195ccb364c30d7271a
public interface P0.I0
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
#1 = Utf8 P0/I0
#2 = Class #1 // P0/I0
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 ()Ljava/lang/Integer;
#7 = Utf8 test
#8 = Utf8 P0/Helper
#9 = Class #8 // P0/Helper
#10 = Utf8 getC2
#11 = Utf8 ()LP0/C2;
#12 = NameAndType #10:#11 // getC2:()LP0/C2;
#13 = Methodref #9.#12 // P0/Helper.getC2:()LP0/C2;
#14 = NameAndType #5:#6 // m:()Ljava/lang/Integer;
#15 = InterfaceMethodref #2.#14 // P0/I0.m:()Ljava/lang/Integer;
#16 = Utf8 main
#17 = Utf8 ([Ljava/lang/String;)V
#18 = NameAndType #7:#6 // test:()Ljava/lang/Integer;
#19 = InterfaceMethodref #2.#18 // P0/I0.test:()Ljava/lang/Integer;
#20 = Utf8 java/lang/System
#21 = Class #20 // java/lang/System
#22 = Utf8 out
#23 = Utf8 Ljava/io/PrintStream;
#24 = NameAndType #22:#23 // out:Ljava/io/PrintStream;
#25 = Fieldref #21.#24 // java/lang/System.out:Ljava/io/PrintStream;
#26 = Utf8 Return value:
#27 = String #26 // Return value:
#28 = Utf8 java/io/PrintStream
#29 = Class #28 // java/io/PrintStream
#30 = Utf8 print
#31 = Utf8 (Ljava/lang/String;)V
#32 = NameAndType #30:#31 // print:(Ljava/lang/String;)V
#33 = Methodref #29.#32 // java/io/PrintStream.print:(Ljava/lang/String;)V
#34 = Utf8 println
#35 = Utf8 (Ljava/lang/Object;)V
#36 = NameAndType #34:#35 // println:(Ljava/lang/Object;)V
#37 = Methodref #29.#36 // java/io/PrintStream.println:(Ljava/lang/Object;)V
#38 = Utf8 Code
{
public abstract java.lang.Integer m();
descriptor: ()Ljava/lang/Integer;
flags: ACC_PUBLIC, ACC_ABSTRACT
public static java.lang.Integer test();
descriptor: ()Ljava/lang/Integer;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: invokestatic #13 // Method P0/Helper.getC2:()LP0/C2;
3: astore_0
4: aload_0
5: invokeinterface #15, 1 // InterfaceMethod m:()Ljava/lang/Integer;
10: areturn
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: invokestatic #19 // InterfaceMethod test:()Ljava/lang/Integer;
3: astore_1
4: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;
7: dup
8: ldc #27 // String Return value:
10: invokevirtual #33 // Method java/io/PrintStream.print:(Ljava/lang/String;)V
13: aload_1
14: invokevirtual #37 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
17: return
}
```
In analyzing the call to `var0.m()` in `P0/I0.test()`, we observe that it uses `invokeinterface`. According to the JVM SE11 specification, specifically section [5.4.6](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.6), “A method is selected with respect to class `C` and the resolved method.” We then examined the method selection logic, which states:
> Otherwise, the selected method is determined by the following lookup procedure:
>
> - If `C` contains a declaration of an instance method `m` that can override `mR` ([§5.4.5](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.5)), then `m` is the selected method.
> - Otherwise, if `C` has a superclass, a search for a declaration of an instance method that can override `mR` is performed, starting with the direct superclass of `C` and continuing with the direct superclass of that class, and so forth, until a method is found or no further superclasses exist. If a method is found, it is the selected method.
Although `C2` is the `Objectref`, its method `m()` is `private` and thus cannot override `I0.m()`. Considering `C2`’s superclass `C1`, which contains `m()`, we referred to section [5.4.5](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.5), which states: “`mA` is marked neither `ACC_PUBLIC` nor `ACC_PROTECTED` nor `ACC_PRIVATE`, and either (a) the declaration of `mA` appears in the same run-time package as the declaration of `mC`, or (b) if `mA` is declared in a class `A` and `mC` is declared in a class `C`, then there exists a method `mB` declared in a class `B` such that `C` is a subclass of `B` and `B` is a subclass of `A` and `mC` can override `mB` and `mB` can override `mA`.” However, since `C1` directly implements `I0` and `C1.m()` is package-private, it cannot override `I0.m()`. Consequently, no method is found during the method selection phase.
Returning to `invokeinterface`, the specification states: “Otherwise, if no method is selected, and there are no maximally-specific superinterface methods of `C` that match the resolved method's name and descriptor and are not `abstract`, *invokeinterface* throws an `AbstractMethodError`.”
Thus, for this test case in HotSpot (11.0.26), the expected outcome is an `AbstractMethodError`, rather than the `IllegalAccessError` observed in the output.
ACTUAL -
The output is as follows:
Hotspot(11.0.26):
```
Exception in thread "main" java.lang.IllegalAccessError: 'java.lang.Integer P0.C2.m()'
at P0.I0.test(Unknown Source)
at P0.I0.main(Unknown Source)
```
OpenJ9(11.0.27):
```
Exception in thread "main" java.lang.AbstractMethodError: P0/I0.m()Ljava/lang/Integer;
at P0.I0.test(Unknown Source)
at P0.I0.main(Unknown Source)
```
---------- BEGIN SOURCE ----------
After obtaining the test cases, you can derive the following test cases through decompilation:
```java
package P0;
import P3.C1;
public class C2 extends C1 {
public C2() {
}
private Integer m() {
return new Integer(2);
}
}
```
```java
package P0;
public class Helper {
public Helper() {
}
public static C2 getC2() {
C2 var0 = new C2();
return var0;
}
}
```
```java
package P0;
import java.io.PrintStream;
public interface I0 {
Integer m();
static Integer test() {
C2 var0 = Helper.getC2();
return var0.m();
}
static void main(String[] var0) {
Integer var1 = test();
PrintStream var10000 = System.out;
var10000.print("Return value: ");
var10000.println(var1);
}
}
```
```java
package P3;
import P0.I0;
public class C1 implements I0 {
public C1() {
}
Integer m() {
return new Integer(1);
}
}
```
```java
package P3;
public class Helper {
public Helper() {
}
public static C1 getC1() {
C1 var0 = new C1();
return var0;
}
}
```
---------- END SOURCE ----------
ADDITIONAL SYSTEM INFORMATION :
OS:
Operating System Name: Windows 11
Operating System Architecture: amd64
Operating System Version: 10.0
OpenJDK version:
java version "11.0.26" 2025-01-21 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.26+7-LTS-187)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.26+7-LTS-187, mixed mode)
openjdk version "11.0.27" 2025-04-15
IBM Semeru Runtime Open Edition 11.0.27.0 (build 11.0.27+6)
Eclipse OpenJ9 VM 11.0.27.0 (build openj9-0.51.0, JRE 11 Windows 11 amd64-64-Bit Compressed References 20250504_1192 (JIT enabled, AOT enabled)
OpenJ9 - 31cf5538b0
OMR - 9bcff94a2
JCL - 3e17c0897e based on jdk-11.0.27+6)
A DESCRIPTION OF THE PROBLEM :
Given a test case, we found that the execution results of this test case on different JVMs are different, the simplified test case can be found below. In summary, Hotspot(11.0.26) threw IllegalAccessError while J9(11.0.27) threw AbstractMethodError.
REGRESSION : Last worked in version 11
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The following code can be used to generate the test cases(.class file) that reproduces the above process:
```java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class BytecodeUtil {
public static void main(String args[]) {
// create package
String baseDir = "./your_dir"; // your base dir
File P0 = new File(baseDir + "/" + "P0");
File P3 = new File(baseDir + "/" + "P3");
P0.mkdirs();
P3.mkdirs();
String P0_C2_bytecodeInStr = "CAFEBABE00000034001201000550302F433207000101000550332F43310700030100063C696E69743E0100032829560C000500060A000400070100016D01001528294C6A6176612F6C616E672F496E74656765723B0100116A6176612F6C616E672F496E746567657207000B0300000002010004284929560C0005000E0A000C000F010004436F6465002100020004000000000002000100050006000100110000001100010001000000052AB70008B10000000000020009000A0001001100000016000300010000000ABB000C59120DB70010B0000000000000" ;
String P0_helper_bytecodeInStr = "CAFEBABE00000034000F01000950302F48656C7065720700010100106A6176612F6C616E672F4F626A6563740700030100063C696E69743E0100032829560C000500060A00040007010005676574433201000928294C50302F43323B01000550302F433207000B0A000C0007010004436F64650021000200040000000000020001000500060001000E0000001100010001000000052AB70008B10000000000090009000A0001000E00000016000200010000000ABB000C59B7000D4B2AB0000000000000" ;
String P0_I0_bytecodeInStr = "CAFEBABE00000034002701000550302F49300700010100106A6176612F6C616E672F4F626A6563740700030100016D01001528294C6A6176612F6C616E672F496E74656765723B0100047465737401000950302F48656C706572070008010005676574433201000928294C50302F43323B0C000A000B0A0009000C0C000500060B0002000E0100046D61696E010016285B4C6A6176612F6C616E672F537472696E673B29560C000700060B000200120100106A6176612F6C616E672F53797374656D0700140100036F75740100154C6A6176612F696F2F5072696E7453747265616D3B0C00160017090015001801000E52657475726E2076616C75653A2008001A0100136A6176612F696F2F5072696E7453747265616D07001C0100057072696E74010015284C6A6176612F6C616E672F537472696E673B29560C001E001F0A001D00200100077072696E746C6E010015284C6A6176612F6C616E672F4F626A6563743B29560C002200230A001D0024010004436F646506010002000400000000000304010005000600000009000700060001002600000017000100010000000BB8000D4B2AB9000F0100B000000000000900100011000100260000001E0003000200000012B800134CB2001959121BB600212BB60025B1000000000000" ;
String P3_C1_bytecodeInStr = "CAFEBABE00000034001401000550332F43310700010100106A6176612F6C616E672F4F626A65637407000301000550302F49300700050100063C696E69743E0100032829560C000700080A000400090100016D01001528294C6A6176612F6C616E672F496E74656765723B0100116A6176612F6C616E672F496E746567657207000D0300000001010004284929560C000700100A000E0011010004436F64650021000200040001000600000002000100070008000100130000001100010001000000052AB7000AB1000000000000000B000C0001001300000016000300010000000ABB000E59120FB70012B0000000000000" ;
String P3_Helper_bytecodeInStr = "CAFEBABE00000034000F01000950332F48656C7065720700010100106A6176612F6C616E672F4F626A6563740700030100063C696E69743E0100032829560C000500060A00040007010005676574433101000928294C50332F43313B01000550332F433107000B0A000C0007010004436F64650021000200040000000000020001000500060001000E0000001100010001000000052AB70008B10000000000090009000A0001000E00000016000200010000000ABB000C59B7000D4B2AB0000000000000" ;
try (FileOutputStream fos = new FileOutputStream(P0.getAbsolutePath() + "/" + "C2.class")) {
byte[] P0_C2_bytecode = hexStringToByteArray(P0_C2_bytecodeInStr);
fos.write(P0_C2_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(P0.getAbsolutePath() + "/" + "Helper.class")) {
byte[] P0_helper_bytecode = hexStringToByteArray(P0_helper_bytecodeInStr);
fos.write(P0_helper_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(P0.getAbsolutePath() + "/" + "I0.class")) {
byte[] P0_I0_bytecode = hexStringToByteArray(P0_I0_bytecodeInStr);
fos.write(P0_I0_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(P3.getAbsolutePath() + "/" + "C1.class")) {
byte[] P3_C1_bytecode = hexStringToByteArray(P3_C1_bytecodeInStr);
fos.write(P3_C1_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(P3.getAbsolutePath() + "/" + "Helper.class")) {
byte[] P3_Helper_bytecode = hexStringToByteArray(P3_Helper_bytecodeInStr);
fos.write(P3_Helper_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
}
public static byte[] hexStringToByteArray(String hexString) {
int length = hexString.length();
byte[] byteArray = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
int byteValue = Integer.parseInt(hexString.substring(i, i + 2), 16);
byteArray[i / 2] = (byte) byteValue;
}
return byteArray;
}
}
```
Note: modify the paths according to your needs.
Repoduce:
>>> path_to_jdk/Hotspot_11.0.26/bin/java -cp . P0.I0
>>> path_to_jdk/openj9/11.0.27/bin/java -cp . P0.I0
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
According to this interesting result, we first decompiled P0.I0 using javap. The results are as follows:
```java
Classfile /D:/Lab/TestJDoc/reduce/Test_JDoc/log/jvm-test/openj9-8/InterfaceSignatureConflictTest/case_21/P0/I0.class
Last modified Jul 3, 2025; size 478 bytes
MD5 checksum f92264b361e06d195ccb364c30d7271a
public interface P0.I0
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
#1 = Utf8 P0/I0
#2 = Class #1 // P0/I0
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 ()Ljava/lang/Integer;
#7 = Utf8 test
#8 = Utf8 P0/Helper
#9 = Class #8 // P0/Helper
#10 = Utf8 getC2
#11 = Utf8 ()LP0/C2;
#12 = NameAndType #10:#11 // getC2:()LP0/C2;
#13 = Methodref #9.#12 // P0/Helper.getC2:()LP0/C2;
#14 = NameAndType #5:#6 // m:()Ljava/lang/Integer;
#15 = InterfaceMethodref #2.#14 // P0/I0.m:()Ljava/lang/Integer;
#16 = Utf8 main
#17 = Utf8 ([Ljava/lang/String;)V
#18 = NameAndType #7:#6 // test:()Ljava/lang/Integer;
#19 = InterfaceMethodref #2.#18 // P0/I0.test:()Ljava/lang/Integer;
#20 = Utf8 java/lang/System
#21 = Class #20 // java/lang/System
#22 = Utf8 out
#23 = Utf8 Ljava/io/PrintStream;
#24 = NameAndType #22:#23 // out:Ljava/io/PrintStream;
#25 = Fieldref #21.#24 // java/lang/System.out:Ljava/io/PrintStream;
#26 = Utf8 Return value:
#27 = String #26 // Return value:
#28 = Utf8 java/io/PrintStream
#29 = Class #28 // java/io/PrintStream
#30 = Utf8 print
#31 = Utf8 (Ljava/lang/String;)V
#32 = NameAndType #30:#31 // print:(Ljava/lang/String;)V
#33 = Methodref #29.#32 // java/io/PrintStream.print:(Ljava/lang/String;)V
#34 = Utf8 println
#35 = Utf8 (Ljava/lang/Object;)V
#36 = NameAndType #34:#35 // println:(Ljava/lang/Object;)V
#37 = Methodref #29.#36 // java/io/PrintStream.println:(Ljava/lang/Object;)V
#38 = Utf8 Code
{
public abstract java.lang.Integer m();
descriptor: ()Ljava/lang/Integer;
flags: ACC_PUBLIC, ACC_ABSTRACT
public static java.lang.Integer test();
descriptor: ()Ljava/lang/Integer;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: invokestatic #13 // Method P0/Helper.getC2:()LP0/C2;
3: astore_0
4: aload_0
5: invokeinterface #15, 1 // InterfaceMethod m:()Ljava/lang/Integer;
10: areturn
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: invokestatic #19 // InterfaceMethod test:()Ljava/lang/Integer;
3: astore_1
4: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;
7: dup
8: ldc #27 // String Return value:
10: invokevirtual #33 // Method java/io/PrintStream.print:(Ljava/lang/String;)V
13: aload_1
14: invokevirtual #37 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
17: return
}
```
In analyzing the call to `var0.m()` in `P0/I0.test()`, we observe that it uses `invokeinterface`. According to the JVM SE11 specification, specifically section [5.4.6](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.6), “A method is selected with respect to class `C` and the resolved method.” We then examined the method selection logic, which states:
> Otherwise, the selected method is determined by the following lookup procedure:
>
> - If `C` contains a declaration of an instance method `m` that can override `mR` ([§5.4.5](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.5)), then `m` is the selected method.
> - Otherwise, if `C` has a superclass, a search for a declaration of an instance method that can override `mR` is performed, starting with the direct superclass of `C` and continuing with the direct superclass of that class, and so forth, until a method is found or no further superclasses exist. If a method is found, it is the selected method.
Although `C2` is the `Objectref`, its method `m()` is `private` and thus cannot override `I0.m()`. Considering `C2`’s superclass `C1`, which contains `m()`, we referred to section [5.4.5](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.5), which states: “`mA` is marked neither `ACC_PUBLIC` nor `ACC_PROTECTED` nor `ACC_PRIVATE`, and either (a) the declaration of `mA` appears in the same run-time package as the declaration of `mC`, or (b) if `mA` is declared in a class `A` and `mC` is declared in a class `C`, then there exists a method `mB` declared in a class `B` such that `C` is a subclass of `B` and `B` is a subclass of `A` and `mC` can override `mB` and `mB` can override `mA`.” However, since `C1` directly implements `I0` and `C1.m()` is package-private, it cannot override `I0.m()`. Consequently, no method is found during the method selection phase.
Returning to `invokeinterface`, the specification states: “Otherwise, if no method is selected, and there are no maximally-specific superinterface methods of `C` that match the resolved method's name and descriptor and are not `abstract`, *invokeinterface* throws an `AbstractMethodError`.”
Thus, for this test case in HotSpot (11.0.26), the expected outcome is an `AbstractMethodError`, rather than the `IllegalAccessError` observed in the output.
ACTUAL -
The output is as follows:
Hotspot(11.0.26):
```
Exception in thread "main" java.lang.IllegalAccessError: 'java.lang.Integer P0.C2.m()'
at P0.I0.test(Unknown Source)
at P0.I0.main(Unknown Source)
```
OpenJ9(11.0.27):
```
Exception in thread "main" java.lang.AbstractMethodError: P0/I0.m()Ljava/lang/Integer;
at P0.I0.test(Unknown Source)
at P0.I0.main(Unknown Source)
```
---------- BEGIN SOURCE ----------
After obtaining the test cases, you can derive the following test cases through decompilation:
```java
package P0;
import P3.C1;
public class C2 extends C1 {
public C2() {
}
private Integer m() {
return new Integer(2);
}
}
```
```java
package P0;
public class Helper {
public Helper() {
}
public static C2 getC2() {
C2 var0 = new C2();
return var0;
}
}
```
```java
package P0;
import java.io.PrintStream;
public interface I0 {
Integer m();
static Integer test() {
C2 var0 = Helper.getC2();
return var0.m();
}
static void main(String[] var0) {
Integer var1 = test();
PrintStream var10000 = System.out;
var10000.print("Return value: ");
var10000.println(var1);
}
}
```
```java
package P3;
import P0.I0;
public class C1 implements I0 {
public C1() {
}
Integer m() {
return new Integer(1);
}
}
```
```java
package P3;
public class Helper {
public Helper() {
}
public static C1 getC1() {
C1 var0 = new C1();
return var0;
}
}
```
---------- END SOURCE ----------