Uploaded image for project: 'Code Tools'
  1. Code Tools
  2. CODETOOLS-7902648

jasm has no clues about how to interpret CONSTANT_MethodHandle_info:reference_kind in an invokedynamic instruction

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • asm_tools_7.0
    • asm_tools_7.0
    • tools
    • None

      Reported by Vladimir Parfinenko <vladimir.parfinenko@gmail.com>:
      There are some problems with generation of CP entries for
      invokedynamic of non-interface metafactory method

      Minimal example:
      ------- Interf.jasm -------
      @+java/lang/FunctionalInterface { }
      public interface Interf
      version 52:0
      {

          public Method callerDynamic:"(LInterf;)LInterf;"
              stack 2 locals 2
              {
                  aload_0;
                  aload_1;
                  invokedynamic InvokeDynamic
      REF_invokeStatic:java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;":bar:"(LInterf;LInterf;)LInterf;"
      MethodType "()Ljava/lang/Object;", MethodHandle
      REF_invokeSpecial:Interf.foo:"(LInterf;)Ljava/lang/Object;",
      MethodType "()Ljava/lang/Object;";
                  areturn;
              }

          public Method callerSpecial:"(LInterf;)LInterf;"
              stack 2 locals 2
              {
                  aload_0;
                  aload_1;
                  invokespecial Interf.foo:"(LInterf;)Ljava/lang/Object;";
                  areturn;
              }

          private synthetic Method foo:"(LInterf;)Ljava/lang/Object;"
              stack 1 locals 2
              {
                  aconst_null;
                  areturn;
              }

          public abstract Method bar:"()Ljava/lang/Object;";

      }
      --------------------------
      The resulting class Interf looks like the following after compilation
      with the latest asmtools (changeset 41):
      ---------- Interf.javap --------------
      Classfile /tmp/asmtools-bugs/Interf.class
        Last modified Mar 30, 2020; size 768 bytes
        MD5 checksum 95fb63d2b77ed98e4fd1a478666a7965
        Compiled from "Interf.jasm"
      public interface Interf
        minor version: 0
        major version: 52
        flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
      Constant pool:
         #1 = Methodref #4.#11 //
      Interf.foo:(LInterf;)Ljava/lang/Object;
         #2 = InvokeDynamic #0:#8 // #0:bar:(LInterf;LInterf;)LInterf;
         #3 = Utf8 (LInterf;)Ljava/lang/Object;
         #4 = Class #18 // Interf
         #5 = Utf8 (LInterf;)LInterf;
         #6 = Utf8 bar
         #7 = Utf8 Interf.jasm
         #8 = NameAndType #6:#14 // bar:(LInterf;LInterf;)LInterf;
         #9 = MethodHandle #6:#28 // invokestatic
      java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
        #10 = Utf8 SourceFile
        #11 = NameAndType #13:#3 // foo:(LInterf;)Ljava/lang/Object;
        #12 = MethodHandle #7:#23 // invokespecial
      Interf.foo:(LInterf;)Ljava/lang/Object;
        #13 = Utf8 foo
        #14 = Utf8 (LInterf;LInterf;)LInterf;
        #15 = NameAndType #16:#29 //
      metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
        #16 = Utf8 metafactory
        #17 = Utf8 callerDynamic
        #18 = Utf8 Interf
        #19 = Class #30 // java/lang/Object
        #20 = Class #31 // java/lang/invoke/LambdaMetafactory
        #21 = Utf8 Ljava/lang/FunctionalInterface;
        #22 = Utf8 RuntimeVisibleAnnotations
        #23 = InterfaceMethodref #4.#11 //
      Interf.foo:(LInterf;)Ljava/lang/Object;
        #24 = MethodType #26 // ()Ljava/lang/Object;
        #25 = Utf8 BootstrapMethods
        #26 = Utf8 ()Ljava/lang/Object;
        #27 = Utf8 callerSpecial
        #28 = InterfaceMethodref #20.#15 //
      java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
        #29 = Utf8
      (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
        #30 = Utf8 java/lang/Object
        #31 = Utf8 java/lang/invoke/LambdaMetafactory
        #32 = Utf8 Code
      {
        public Interf callerDynamic(Interf);
          descriptor: (LInterf;)LInterf;
          flags: ACC_PUBLIC
          Code:
            stack=2, locals=2, args_size=2
               0: aload_0
               1: aload_1
               2: invokedynamic #2, 0 // InvokeDynamic
      #0:bar:(LInterf;LInterf;)LInterf;
               7: areturn

        public Interf callerSpecial(Interf);
          descriptor: (LInterf;)LInterf;
          flags: ACC_PUBLIC
          Code:
            stack=2, locals=2, args_size=2
               0: aload_0
               1: aload_1
               2: invokespecial #1 // Method
      foo:(LInterf;)Ljava/lang/Object;
               5: areturn

        public abstract java.lang.Object bar();
          descriptor: ()Ljava/lang/Object;
          flags: ACC_PUBLIC, ACC_ABSTRACT
      }
      SourceFile: "Interf.jasm"
      RuntimeVisibleAnnotations:
        0: #21()
      BootstrapMethods:
        0: #9 invokestatic
      java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
          Method arguments:
            #24 ()Ljava/lang/Object;
            #12 invokespecial Interf.foo:(LInterf;)Ljava/lang/Object;
            #24 ()Ljava/lang/Object;

      ------- Main.java ------
      public class Main implements Interf {
         public static void main(String[] var0) {
            Main x = new Main();
            try {
                System.out.println("Dynamic");
                x.callerDynamic(x);
                System.out.println("OK");
            } catch (Throwable e) {
                e.printStackTrace(System.out);
            }
            try {
                System.out.println("Special");
                x.callerSpecial(x);
                System.out.println("OK");
            } catch (Throwable e) {
                e.printStackTrace(System.out);
            }
         }

         public Object bar() {
            return null;
         }
      }
      ---------------------------------


      1) 0-th boostrap method references LambdaMetafactory.metafactory() as
      InterfaceMethodRef #9 but the declaring class is not an interface.

      unning this sample on JDK-13 gives the output:
      ------ stdout -------
      Dynamic
      java.lang.IncompatibleClassChangeError: Inconsistent constant pool
      data in classfile for class java/lang/invoke/LambdaMetafactory. Method
      'java.lang.invoke.CallSite
      metafactory(java.lang.invoke.MethodHandles$Lookup, java.lang.String,
      java.lang.invoke.MethodType, java.lang.invoke.MethodType,
      java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)' at index
      9 is CONSTANT_InterfaceMethodRef and should be CONSTANT_MethodRef
              at Interf.callerDynamic(Interf.jasm)
              at Main.main(Main.java:6)

            lkuskov Leonid Kuskov
            lkuskov Leonid Kuskov
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: