-
Bug
-
Resolution: Duplicate
-
P3
-
None
-
8u101
FULL PRODUCT VERSION :
java version "1.8.0_101"
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux paloalto 4.4.0-31-generic #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
In rare cases, constant variables are not resolved at compile time (as mandated by JLS 13.1 bullet point 3) and a reference to the field is still present in the code.
The behavior seems to be triggered by a ternary operator and could not be observed in other cases.
REGRESSION. Last worked in version 7u80
ADDITIONAL REGRESSION INFORMATION:
I did not perform full regression testing, only confirmed that the problem does not occur with a Java 7 compiler (1.7.0_80).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the attached source code with javac.
Use javap to inspect the resulting byte code.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The fields ENABLED and DISABLED should not be referenced in the code using getstatic instructions, but their constant value should have been resolved at compile time and used in code via ldc instructions.
ACTUAL -
Result of javap. You can see that the fields are still referenced with getstatic instructions, although they have a ConstantValue attribute.
javap -p -v -cp . MyTest
Classfile xxx/MyTest.class
Last modified Sep 8, 2016; size 1142 bytes
MD5 checksum 2b2abc16281f5f368a40eb0c6e7d550f
Compiled from "MyTest.java"
public class MyTest
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #16.#40 // java/lang/Object."<init>":()V
#2 = String #41 // A
#3 = Methodref #42.#43 // java/lang/String.equals:(Ljava/lang/Object;)Z
#4 = Class #44 // java/lang/StringBuilder
#5 = Methodref #4.#40 // java/lang/StringBuilder."<init>":()V
#6 = Methodref #4.#45 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#7 = Methodref #4.#46 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#8 = String #47 // F
#9 = Methodref #15.#48 // MyTest.isEnabled:(Ljava/lang/String;)Z
#10 = Fieldref #15.#49 // MyTest.ENABLED:Ljava/lang/String;
#11 = Fieldref #15.#50 // MyTest.DISABLED:Ljava/lang/String;
#12 = Methodref #15.#51 // MyTest.getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
#13 = Fieldref #52.#53 // java/lang/System.out:Ljava/io/PrintStream;
#14 = Methodref #54.#55 // java/io/PrintStream.println:(Ljava/lang/String;)V
#15 = Class #56 // MyTest
#16 = Class #57 // java/lang/Object
#17 = Utf8 ENABLED
#18 = Utf8 Ljava/lang/String;
#19 = Utf8 ConstantValue
#20 = String #58 // Y
#21 = Utf8 DISABLED
#22 = String #59 // N
#23 = Utf8 <init>
#24 = Utf8 ()V
#25 = Utf8 Code
#26 = Utf8 LineNumberTable
#27 = Utf8 isEnabled
#28 = Utf8 (Ljava/lang/String;)Z
#29 = Utf8 StackMapTable
#30 = Utf8 getString
#31 = Utf8 (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
#32 = Utf8 main
#33 = Utf8 ([Ljava/lang/String;)V
#34 = Class #60 // java/lang/String
#35 = Class #61 // "[Ljava/lang/String;"
#36 = Utf8 Exceptions
#37 = Class #62 // java/lang/Exception
#38 = Utf8 SourceFile
#39 = Utf8 MyTest.java
#40 = NameAndType #23:#24 // "<init>":()V
#41 = Utf8 A
#42 = Class #60 // java/lang/String
#43 = NameAndType #63:#64 // equals:(Ljava/lang/Object;)Z
#44 = Utf8 java/lang/StringBuilder
#45 = NameAndType #65:#66 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#46 = NameAndType #67:#68 // toString:()Ljava/lang/String;
#47 = Utf8 F
#48 = NameAndType #27:#28 // isEnabled:(Ljava/lang/String;)Z
#49 = NameAndType #17:#18 // ENABLED:Ljava/lang/String;
#50 = NameAndType #21:#18 // DISABLED:Ljava/lang/String;
#51 = NameAndType #30:#31 // getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
#52 = Class #69 // java/lang/System
#53 = NameAndType #70:#71 // out:Ljava/io/PrintStream;
#54 = Class #72 // java/io/PrintStream
#55 = NameAndType #73:#74 // println:(Ljava/lang/String;)V
#56 = Utf8 MyTest
#57 = Utf8 java/lang/Object
#58 = Utf8 Y
#59 = Utf8 N
#60 = Utf8 java/lang/String
#61 = Utf8 [Ljava/lang/String;
#62 = Utf8 java/lang/Exception
#63 = Utf8 equals
#64 = Utf8 (Ljava/lang/Object;)Z
#65 = Utf8 append
#66 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#67 = Utf8 toString
#68 = Utf8 ()Ljava/lang/String;
#69 = Utf8 java/lang/System
#70 = Utf8 out
#71 = Utf8 Ljava/io/PrintStream;
#72 = Utf8 java/io/PrintStream
#73 = Utf8 println
#74 = Utf8 (Ljava/lang/String;)V
{
private static final java.lang.String ENABLED;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL
ConstantValue: String Y
private static final java.lang.String DISABLED;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL
ConstantValue: String N
public MyTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
private static boolean isEnabled(java.lang.String);
descriptor: (Ljava/lang/String;)Z
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: ldc #2 // String A
3: invokevirtual #3 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
6: ifeq 11
9: iconst_1
10: ireturn
11: iconst_0
12: ireturn
LineNumberTable:
line 9: 0
line 10: 11
StackMapTable: number_of_entries = 1
frame_type = 11 /* same */
private static java.lang.String getString(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=2, args_size=2
0: new #4 // class java/lang/StringBuilder
3: dup
4: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
7: aload_0
8: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_1
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
18: areturn
LineNumberTable:
line 15: 0
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=2, 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: return
LineNumberTable:
line 20: 0
line 21: 23
line 25: 30
StackMapTable: number_of_entries = 2
frame_type = 80 /* same_locals_1_stack_item */
stack = [ class java/lang/String ]
frame_type = 255 /* full_frame */
offset_delta = 2
locals = [ class "[Ljava/lang/String;" ]
stack = [ class java/lang/String, class java/lang/String ]
Exceptions:
throws java.lang.Exception
}
SourceFile: "MyTest.java"
REPRODUCIBILITY :
This bug can be reproduced rarely.
---------- BEGIN SOURCE ----------
public class MyTest
{
private static final String ENABLED = "Y";
private static final String DISABLED = "N";
private static boolean isEnabled(String key)
{
if (key.equals("A")) return true;
else return false;
}
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);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Workaround seems to be to store the result of the ternary operator into a temporary variable.
java version "1.8.0_101"
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux paloalto 4.4.0-31-generic #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
In rare cases, constant variables are not resolved at compile time (as mandated by JLS 13.1 bullet point 3) and a reference to the field is still present in the code.
The behavior seems to be triggered by a ternary operator and could not be observed in other cases.
REGRESSION. Last worked in version 7u80
ADDITIONAL REGRESSION INFORMATION:
I did not perform full regression testing, only confirmed that the problem does not occur with a Java 7 compiler (1.7.0_80).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the attached source code with javac.
Use javap to inspect the resulting byte code.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The fields ENABLED and DISABLED should not be referenced in the code using getstatic instructions, but their constant value should have been resolved at compile time and used in code via ldc instructions.
ACTUAL -
Result of javap. You can see that the fields are still referenced with getstatic instructions, although they have a ConstantValue attribute.
javap -p -v -cp . MyTest
Classfile xxx/MyTest.class
Last modified Sep 8, 2016; size 1142 bytes
MD5 checksum 2b2abc16281f5f368a40eb0c6e7d550f
Compiled from "MyTest.java"
public class MyTest
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #16.#40 // java/lang/Object."<init>":()V
#2 = String #41 // A
#3 = Methodref #42.#43 // java/lang/String.equals:(Ljava/lang/Object;)Z
#4 = Class #44 // java/lang/StringBuilder
#5 = Methodref #4.#40 // java/lang/StringBuilder."<init>":()V
#6 = Methodref #4.#45 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#7 = Methodref #4.#46 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#8 = String #47 // F
#9 = Methodref #15.#48 // MyTest.isEnabled:(Ljava/lang/String;)Z
#10 = Fieldref #15.#49 // MyTest.ENABLED:Ljava/lang/String;
#11 = Fieldref #15.#50 // MyTest.DISABLED:Ljava/lang/String;
#12 = Methodref #15.#51 // MyTest.getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
#13 = Fieldref #52.#53 // java/lang/System.out:Ljava/io/PrintStream;
#14 = Methodref #54.#55 // java/io/PrintStream.println:(Ljava/lang/String;)V
#15 = Class #56 // MyTest
#16 = Class #57 // java/lang/Object
#17 = Utf8 ENABLED
#18 = Utf8 Ljava/lang/String;
#19 = Utf8 ConstantValue
#20 = String #58 // Y
#21 = Utf8 DISABLED
#22 = String #59 // N
#23 = Utf8 <init>
#24 = Utf8 ()V
#25 = Utf8 Code
#26 = Utf8 LineNumberTable
#27 = Utf8 isEnabled
#28 = Utf8 (Ljava/lang/String;)Z
#29 = Utf8 StackMapTable
#30 = Utf8 getString
#31 = Utf8 (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
#32 = Utf8 main
#33 = Utf8 ([Ljava/lang/String;)V
#34 = Class #60 // java/lang/String
#35 = Class #61 // "[Ljava/lang/String;"
#36 = Utf8 Exceptions
#37 = Class #62 // java/lang/Exception
#38 = Utf8 SourceFile
#39 = Utf8 MyTest.java
#40 = NameAndType #23:#24 // "<init>":()V
#41 = Utf8 A
#42 = Class #60 // java/lang/String
#43 = NameAndType #63:#64 // equals:(Ljava/lang/Object;)Z
#44 = Utf8 java/lang/StringBuilder
#45 = NameAndType #65:#66 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#46 = NameAndType #67:#68 // toString:()Ljava/lang/String;
#47 = Utf8 F
#48 = NameAndType #27:#28 // isEnabled:(Ljava/lang/String;)Z
#49 = NameAndType #17:#18 // ENABLED:Ljava/lang/String;
#50 = NameAndType #21:#18 // DISABLED:Ljava/lang/String;
#51 = NameAndType #30:#31 // getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
#52 = Class #69 // java/lang/System
#53 = NameAndType #70:#71 // out:Ljava/io/PrintStream;
#54 = Class #72 // java/io/PrintStream
#55 = NameAndType #73:#74 // println:(Ljava/lang/String;)V
#56 = Utf8 MyTest
#57 = Utf8 java/lang/Object
#58 = Utf8 Y
#59 = Utf8 N
#60 = Utf8 java/lang/String
#61 = Utf8 [Ljava/lang/String;
#62 = Utf8 java/lang/Exception
#63 = Utf8 equals
#64 = Utf8 (Ljava/lang/Object;)Z
#65 = Utf8 append
#66 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#67 = Utf8 toString
#68 = Utf8 ()Ljava/lang/String;
#69 = Utf8 java/lang/System
#70 = Utf8 out
#71 = Utf8 Ljava/io/PrintStream;
#72 = Utf8 java/io/PrintStream
#73 = Utf8 println
#74 = Utf8 (Ljava/lang/String;)V
{
private static final java.lang.String ENABLED;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL
ConstantValue: String Y
private static final java.lang.String DISABLED;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL
ConstantValue: String N
public MyTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
private static boolean isEnabled(java.lang.String);
descriptor: (Ljava/lang/String;)Z
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: ldc #2 // String A
3: invokevirtual #3 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
6: ifeq 11
9: iconst_1
10: ireturn
11: iconst_0
12: ireturn
LineNumberTable:
line 9: 0
line 10: 11
StackMapTable: number_of_entries = 1
frame_type = 11 /* same */
private static java.lang.String getString(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=2, args_size=2
0: new #4 // class java/lang/StringBuilder
3: dup
4: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
7: aload_0
8: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_1
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
18: areturn
LineNumberTable:
line 15: 0
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=2, 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: return
LineNumberTable:
line 20: 0
line 21: 23
line 25: 30
StackMapTable: number_of_entries = 2
frame_type = 80 /* same_locals_1_stack_item */
stack = [ class java/lang/String ]
frame_type = 255 /* full_frame */
offset_delta = 2
locals = [ class "[Ljava/lang/String;" ]
stack = [ class java/lang/String, class java/lang/String ]
Exceptions:
throws java.lang.Exception
}
SourceFile: "MyTest.java"
REPRODUCIBILITY :
This bug can be reproduced rarely.
---------- BEGIN SOURCE ----------
public class MyTest
{
private static final String ENABLED = "Y";
private static final String DISABLED = "N";
private static boolean isEnabled(String key)
{
if (key.equals("A")) return true;
else return false;
}
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);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Workaround seems to be to store the result of the ternary operator into a temporary variable.
- duplicates
-
JDK-8066871 java.lang.VerifyError: Bad local variable type - local final String
-
- Closed
-