I ran into an issue while manipulating some bytecode, where a certain final
String
constant was not inlined by the java compiler (Java 8), see the example below:
public class MyTest
{
private static final String ENABLED = "Y";
private static final String DISABLED = "N";
private static boolean isEnabled(String key) {
return key.equals("A");
}
private static String getString(String key, String value) {
return key + value;
}
public static void main(String[] args) throws Exception {
String flag = getString("F", isEnabled("A") ? ENABLED : DISABLED);
System.out.println(flag);
String flag2 = getString("F", isEnabled("A") ? ENABLED : DISABLED);
System.out.println(flag2);
}
}
Resulting bytecode with javac (1.8.0_101)
public static void main(java.lang.String[]) throws java.lang.Exception;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: ldc #8 // String F
2: ldc #2 // String A
4: invokestatic #9 // Method isEnabled:(Ljava/lang/String;)Z
7: ifeq 16
10: getstatic #10 // Field ENABLED:Ljava/lang/String;
13: goto 19
16: getstatic #11 // Field DISABLED:Ljava/lang/String;
19: invokestatic #12 // Method getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
22: astore_1
23: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_1
27: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: ldc #8 // String F
32: ldc #2 // String A
34: invokestatic #9 // Method isEnabled:(Ljava/lang/String;)Z
37: ifeq 46
40: getstatic #10 // Field ENABLED:Ljava/lang/String;
43: goto 49
46: getstatic #11 // Field DISABLED:Ljava/lang/String;
49: invokestatic #12 // Method getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
52: astore_2
53: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
56: aload_2
57: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
60: return
You can see that the second time the fields ENABLED
and DISABLED
are being accessed, the compiler did not inline their values (using ldc
), but instead used getstatic
to access the field directly. Testing it with other compilers (Java 7, Eclipse) did not trigger the same behavior and the constants were always inlined.
Can this be considered a compiler bug, or is it allowed to not inline string constants all the time according to the JLS?