Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8165750

Constant variable (type string) still referenced in code, violating JLS 13.1

    XMLWordPrintable

Details

    Description

      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.

      Attachments

        Issue Links

          Activity

            People

              fmatte Fairoz Matte
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: