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

[lworld] javac doesn't set ACC_STRICT to final synthetic fields in value classes

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • None
    • repo-valhalla
    • tools

      With JDK-8330582, the JVM starts to enforce new field modifiers rules from JEP 401, notably:
      "A field that has set ACC_STRICT must also have set ACC_FINAL."
      and
      "Each field of a value class must have exactly one of its ACC_STATIC or ACC_STRICT flags set.".

      Enforcing those rules shows an issue with javac: when generating final synthetic fields in value classes, the ACC_STRICT flag is not set.

      Reproducer:

      public class NestedTest {
          value class MyValue {
      int i = 0;

      public String toString() {
      return "MyValue("+i+","+outerInt+")";
      }
          }

          int outerInt = 42;
          MyValue v = new MyValue();

          public static void main(String[] args) {
      NestedTest nt = new NestedTest();
          }
      }

      Error reported by the JVM (with JDK-8330582 changes in):

      Exception in thread "main" java.lang.ClassFormatError: Illegal field modifiers in class NestedTest$MyValue: 0x1010
      at java.base/java.lang.ClassLoader.defineClass1(Native Method)
      at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1023)
      at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
      at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862)
      at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)
      at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)
      at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
      at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
      at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
      at NestedTest.<init>(NestedTest.java:11)
      at NestedTest.main(NestedTest.java:14)


      Decompiling the value class shows the illegal field modifiers set for field this$0 :

      Classfile [...]/NestedTest$MyValue.class
        Last modified Apr 18, 2024; size 965 bytes
        SHA-256 checksum e3a71b30c8be9b0529a3297b2bc499abf9a188455a5c4a5463e8217e89520040
        Compiled from "NestedTest.java"
      final value class NestedTest$MyValue
        minor version: 65535
        major version: 66
        flags: (0x0010) ACC_FINAL
        this_class: #2 // NestedTest$MyValue
        super_class: #12 // java/lang/Object
        interfaces: 0, fields: 2, methods: 2, attributes: 4
      Constant pool:
         #1 = Fieldref #2.#3 // NestedTest$MyValue.this$0:LNestedTest;
         #2 = Class #4 // NestedTest$MyValue
         #3 = NameAndType #5:#6 // this$0:LNestedTest;
         #4 = Utf8 NestedTest$MyValue
         #5 = Utf8 this$0
         #6 = Utf8 LNestedTest;
         #7 = Fieldref #2.#8 // NestedTest$MyValue.i:I
         #8 = NameAndType #9:#10 // i:I
         #9 = Utf8 i
        #10 = Utf8 I
        #11 = Methodref #12.#13 // java/lang/Object."<init>":()V
        #12 = Class #14 // java/lang/Object
        #13 = NameAndType #15:#16 // "<init>":()V
        #14 = Utf8 java/lang/Object
        #15 = Utf8 <init>
        #16 = Utf8 ()V
        #17 = Fieldref #18.#19 // NestedTest.outerInt:I
        #18 = Class #20 // NestedTest
        #19 = NameAndType #21:#10 // outerInt:I
        #20 = Utf8 NestedTest
        #21 = Utf8 outerInt
        #22 = InvokeDynamic #0:#23 // #0:makeConcatWithConstants:(I)Ljava/lang/String;
        #23 = NameAndType #24:#25 // makeConcatWithConstants:(I)Ljava/lang/String;
        #24 = Utf8 makeConcatWithConstants
        #25 = Utf8 (I)Ljava/lang/String;
        #26 = Utf8 ConstantValue
        #27 = Integer 0
        #28 = Utf8 (LNestedTest;)V
        #29 = Utf8 Code
        #30 = Utf8 LineNumberTable
        #31 = Utf8 MethodParameters
        #32 = Utf8 toString
        #33 = Utf8 ()Ljava/lang/String;
        #34 = Utf8 SourceFile
        #35 = Utf8 NestedTest.java
        #36 = Utf8 NestHost
        #37 = Utf8 BootstrapMethods
        #38 = String #39 // MyValue(0,\u0001)
        #39 = Utf8 MyValue(0,\u0001)
        #40 = MethodHandle 6:#41 // REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Looku
      p;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
        #41 = Methodref #42.#43 // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/Stri
      ng;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
        #42 = Class #44 // java/lang/invoke/StringConcatFactory
        #43 = NameAndType #24:#45 // makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava
      /lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
        #44 = Utf8 java/lang/invoke/StringConcatFactory
        #45 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lan
      g/invoke/CallSite;
        #46 = Utf8 InnerClasses
        #47 = Utf8 MyValue
        #48 = Class #49 // java/lang/invoke/MethodHandles$Lookup
        #49 = Utf8 java/lang/invoke/MethodHandles$Lookup
        #50 = Class #51 // java/lang/invoke/MethodHandles
        #51 = Utf8 java/lang/invoke/MethodHandles
        #52 = Utf8 Lookup
      {
        final strictfp int i;
          descriptor: I
          flags: (0x0810) ACC_FINAL, ACC_STRICT
          ConstantValue: int 0

        final NestedTest this$0;
          descriptor: LNestedTest;
          flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC

        NestedTest$MyValue(NestedTest);
          descriptor: (LNestedTest;)V
          flags: (0x0000)
          Code:
            stack=2, locals=2, args_size=2
               0: aload_0
               1: aload_1
               2: putfield #1 // Field this$0:LNestedTest;
               5: aload_0
               6: iconst_0
               7: putfield #7 // Field i:I
              10: aload_0
              11: invokespecial #11 // Method java/lang/Object."<init>":()V
              14: return
            LineNumberTable:
              line 2: 0
              line 3: 5
              line 2: 10
          MethodParameters:
            Name Flags
            <no name> final mandated

        public java.lang.String toString();
          descriptor: ()Ljava/lang/String;
          flags: (0x0001) ACC_PUBLIC
          Code:
            stack=1, locals=1, args_size=1
               0: aload_0
               1: getfield #1 // Field this$0:LNestedTest;
               4: getfield #17 // Field NestedTest.outerInt:I
               7: invokedynamic #22, 0 // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
              12: areturn
            LineNumberTable:
              line 6: 0
      }
      SourceFile: "NestedTest.java"
      NestHost: class NestedTest
      BootstrapMethods:
        0: #40 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invok
      e/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
          Method arguments:
            #38 MyValue(0,\u0001)
      InnerClasses:
        final #47= #2 of #18; // MyValue=class NestedTest$MyValue of class NestedTest
        public static final #52= #48 of #50; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles


      Another minor issue, for field 'i', javap prints " final strictfp int i;" when it should print " final strict int i;".

            vromero Vicente Arturo Romero Zaldivar
            fparain Frederic Parain
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: