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

Bytecodes API produces an incorrect stackmap for value arrays

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P3
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: tools

      Description

      Trying to use the Bytecodes API to manipulatevalue arrays, it seems that the stack map generated by the CodeBuilder is incorrect. The generated class file is rejected by the verifier, and after disassembling the class file, the verifier seems to be right.

      Here’s the code to generate the method:

      static void testExecutionStackToValueArray(Class<?> valueClass, Class<?> containerClass) throws Throwable {
             final int ITERATIONS = 100;
             String sig = "()Q" + valueClass.getName() + ";";
             final String signature = sig.replace('.', '/');
             final String arraySignature = "[Q" + valueClass.getName().replace('.', '/') + ";";
             System.out.println(arraySignature);
             MethodHandle fromExecStackToValueArray = MethodHandleBuilder.loadCode(
                     LOOKUP,
                     "execStackToValueArray",
                     MethodType.methodType(boolean.class),
                     CODE -> {
                         CODE
                                 .invokestatic(System.class, "gc", "()V", false)
                                 .new_(containerClass)
                                 .dup()
                                 .invoke(MacroCodeBuilder.InvocationKind.INVOKESPECIAL, containerClass, "<init>", "()V", false)
                                 .astore_1()
                                 .ldc(ITERATIONS * 3)
                                 .anewarray(valueClass)
                                 .astore_2()
                                 .iconst_m1()
                                 .istore_3()
                                 .label("loop")
                                 .iload_3()
                                 .ldc(ITERATIONS)
                                 .ifcmp(TypeTag.I, CondKind.EQ, "end")
                                 .iinc(3, 1)
                                 .goto_("loop")
                                 .label("end")
                                 .iconst_1()
                                 .return_(TypeTag.Z)
                                 .label("failed")
                                 .iconst_0()
                                 .return_(TypeTag.Z);
                     });
             boolean result = (boolean) fromExecStackToValueArray.invokeExact();
             System.out.println(result);
             assertTrue(result, "Invariant");
         }


      And here’s the output of javap for the generated class file:


      public class execStackToValueArray
       minor version: 0
       major version: 52
       flags: (0x0001) ACC_PUBLIC
       this_class: #24 // execStackToValueArray
       super_class: #2 // java/lang/Object
       interfaces: 0, fields: 0, methods: 1, attributes: 0
      Constant pool:
        #1 = Utf8 java/lang/Object
        #2 = Class #1 // java/lang/Object
        #3 = Utf8 java/lang/System
        #4 = Class #3 // java/lang/System
        #5 = Utf8 gc
        #6 = Utf8 ()V
        #7 = NameAndType #5:#6 // gc:()V
        #8 = Methodref #4.#7 // java/lang/System.gc:()V
        #9 = Utf8 runtime/valhalla/valuetypes/ContainerValue1
       #10 = Class #9 // runtime/valhalla/valuetypes/ContainerValue1
       #11 = Utf8 <init>
       #12 = NameAndType #11:#6 // "<init>":()V
       #13 = Methodref #10.#12 // runtime/valhalla/valuetypes/ContainerValue1."<init>":()V
       #14 = Integer 300
       #15 = Utf8 ;Qruntime/valhalla/valuetypes/TestValue1;
       #16 = Class #15 // ";Qruntime/valhalla/valuetypes/TestValue1;"
       #17 = Utf8 [[Qruntime/valhalla/valuetypes/TestValue1;
       #18 = Class #17 // "[[Qruntime/valhalla/valuetypes/TestValue1;"
       #19 = Integer 100
       #20 = Utf8 Code
       #21 = Utf8 StackMapTable
       #22 = Utf8 execStackToValueArray
       #23 = Utf8 ()Z
       #24 = Class #22 // execStackToValueArray
      {
       public static boolean execStackToValueArray();
         descriptor: ()Z
         flags: (0x0009) ACC_PUBLIC, ACC_STATIC
         Code:
           stack=2, locals=4, args_size=0
              0: invokestatic #8 // Method java/lang/System.gc:()V
              3: new #10 // class runtime/valhalla/valuetypes/ContainerValue1
              6: dup
              7: invokespecial #13 // Method runtime/valhalla/valuetypes/ContainerValue1."<init>":()V
             10: astore_1
             11: ldc #14 // int 300
             13: anewarray #16 // class ";Qruntime/valhalla/valuetypes/TestValue1;"
             16: astore_2
             17: iconst_m1
             18: istore_3
             19: iload_3
             20: ldc #19 // int 100
             22: if_icmpeq 31
             25: iinc 3, 1
             28: goto 19
             31: iconst_1
             32: ireturn
             33: iconst_0
             34: ireturn
           StackMapTable: number_of_entries = 3
             frame_type = 255 /* full_frame */
               offset_delta = 19
               locals = [ top, class runtime/valhalla/valuetypes/ContainerValue1, class "[[Qruntime/valhalla/valuetypes/TestValue1;", int ]
               stack = []
             frame_type = 11 /* same */
             frame_type = 1 /* same */
      }


      In the stack map, there’s an entry with a 2 dimensions value array, but the method creates only a single dimension value array.

      The verifier detects the mismatch:

      java.lang.IllegalStateException: java.lang.VerifyError: Instruction type does not match stack map
      Exception Details:
       Location:
         runtime/valhalla/valuetypes/execStackToValueArray.execStackToValueArray()Z @19: iload_3
       Reason:
         Type '[Qruntime/valhalla/valuetypes/TestValue1;' (current frame, locals[2]) is not assignable to '[[Qruntime/valhalla/valuetypes/TestValue1;' (stack map, locals[2])
       Current Frame:
         bci: @19
         flags: { }
         locals: { top, 'runtime/valhalla/valuetypes/ContainerValue1', '[Qruntime/valhalla/valuetypes/TestValue1;', integer }
         stack: { }
       Stackmap Frame:
         bci: @19
         flags: { }
         locals: { top, 'runtime/valhalla/valuetypes/ContainerValue1', '[[Qruntime/valhalla/valuetypes/TestValue1;', integer }
         stack: { }
       Bytecode:
         0000000: b800 08bb 000a 59b7 000d 4c12 0ebd 0010
         0000010: 4d02 3e1d 1213 9f00 0984 0301 a7ff f704
         0000020: ac03 ac
       Stackmap Table:
         full_frame(@19,{Top,Object[#10],Object[#18],Integer},{})
         same_frame(@31)
         same_frame(@33)

      at java.base/jdk.experimental.value.MethodHandleBuilder.loadCode(MethodHandleBuilder.java:105)
      at java.base/jdk.experimental.value.MethodHandleBuilder.loadCode(MethodHandleBuilder.java:72)
      at java.base/jdk.experimental.value.MethodHandleBuilder.loadCode(MethodHandleBuilder.java:67)
      at runtime.valhalla.valuetypes.ValueTypesTest.testExecutionStackToValueArray(ValueTypesTest.java:307)
      at runtime.valhalla.valuetypes.ValueTypesTest.main(ValueTypesTest.java:84)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.base/java.lang.reflect.Method.invoke(Method.java:564)
      at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:115)
      at java.base/java.lang.Thread.run(Thread.java:844)
      Caused by: java.lang.VerifyError: Instruction type does not match stack map

        Attachments

          Activity

            People

            • Assignee:
              fparain Frederic Parain
              Reporter:
              fparain Frederic Parain
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: