Please consider the following class:
class Eq {
public static void main(String[] args) {
System.out.println("" == ".".substring(1));
}
}
The example is supposed to show that multiple copies of the empty string may exist in memory. I still have an old OpenJDK 11 where the program outputs false as expected. Under OpenJDK 15, the program outputs true. The generated bytecode for the class files looks similar (even though they differ in register values):
Java 11:
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #13 // String
5: ldc #15 // String .
7: iconst_1
8: invokevirtual #17 // Method java/lang/String.substring:(I)Ljava/lang/String;
11: if_acmpne 18
14: iconst_1
15: goto 19
18: iconst_0
19: invokevirtual #23 // Method java/io/PrintStream.println:(Z)V
22: return
Java 15:
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String
5: ldc #4 // String .
7: iconst_1
8: invokevirtual #5 // Method java/lang/String.substring:(I)Ljava/lang/String;
11: if_acmpne 18
14: iconst_1
15: goto 19
18: iconst_0
19: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
22: return
I tried to exclude static compiler optimizations by reading "." from stdin but this does not change the outcome. I have tried to disable the JIT via -Djava.compiler=NONE and played around with adjusting the string table size via -XX:StringTableSize=100000. I now have the following questions:
- Can someone reproduce the issue (i.e. did I do it correctly? I can provide the class files if that helps)
- How do I find out the exact reason for the different behaviour?
- What (in your opinion) is the source for the different behaviour?
I think just strategies to approach how to find the reason for the behaviour that don't answer the question might also be interesting.