如何 bootstrap 与 ObjectWeb2 ASM 的接口方法引用

How to bootstrap interface method reference with ObjectWeb2 ASM

我正在尝试修复 Groovy 中对接口方法引用的元工厂调用:https://issues.apache.org/jira/browse/GROOVY-9853

给出小Java程序

public class J {
  public static void main(String[] args) {
    java.util.function.ToIntFunction<CharSequence> f = CharSequence::length;
    f.applyAsInt("");
  }
}

编译器编写这个bootstrap方法:

Bootstrap methods:
  0 : # 58 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:
        #59 (Ljava/lang/Object;)I
        #66 null
        #68 (Ljava/lang/CharSequence;)I

给定一个非常相似的Groovy程序

class G {
  @groovy.transform.CompileStatic
  static main(args) {
    java.util.function.ToIntFunction<CharSequence> f = CharSequence::length
    f.applyAsInt("")
  }
}

groovy 编译器编写此 bootstrap 方法:

Bootstrap methods:
  0 : # 47 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:
        #31 (Ljava/lang/Object;)I
        #38 java/lang/CharSequence.length:()I
        #40 (Ljava/lang/CharSequence;)I

第二个常量池条目对于 java 为“空”,对于 groovy 为“java/lang/CharSequence.length:()I”。这是导致链接问题中提到的 ClassFormatError 的常量池条目。我正在尝试更改 bootstrap 方法输出,这是使用 ASM 完成的,如下所示:

        methodVisitor.visitInvokeDynamicInsn(
                "applyAsInt",
                "()Ljava/util/function/ToIntFunction;",
                new Handle(
                    Opcodes.H_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;",
                    isInterface // false because enclosing class "G" is not an interface
                ),
                createBootstrapMethodArguments(
                        "()Ljava/util/function/ToIntFunction;",
                        Opcodes.H_INVOKEVIRTUAL,
                        typeOrTargetRefType, // CharSequence
                        methodRefMethod, // CharSequence#length
                        false
                ) // 3 arguments: [Type("(Ljava/lang/Object;)I"), Handle("java/lang/CharSequence.length()I (5 itf)"), Type("(Ljava/lang/CharSequence;)I")]
        );

    Object[] createBootstrapMethodArguments(String abstractMethodDesc, int insn, ClassNode methodOwnerClassNode, MethodNode methodNode, boolean serializable) {
        List<Object> arguments = new ArrayList<>(5);
        arguments.add(Type.getType(abstractMethodDesc));

        arguments.add(new Handle(
                insn,
                BytecodeHelper.getClassInternalName(methodOwnerClassNode.getName()),
                methodNode.getName(),
                BytecodeHelper.getMethodDescriptor(methodNode),
                methodOwnerClassNode.isInterface()));

        arguments.add(Type.getType(BytecodeHelper.getMethodDescriptor(methodNode.getReturnType(),
                (Parameter[]) methodNode.getNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE))));

        if (serializable) {
            arguments.add(5);
            arguments.add(0);
        }

        return arguments.toArray();
    }

bootstrap 方法参数是否需要不同?我不太清楚 java 在常量 table 中的“null”与根据类型和句柄发送给 ASM 的内容之间的联系。

这里是 javap 输出:


class J
  minor version: 0
  major version: 52
  flags: (0x0020) ACC_SUPER
  this_class: #1                          // J
  super_class: #3                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 3
Constant pool:
   #1 = Class              #2             // J
   #2 = Utf8               J
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LJ;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = InvokeDynamic      #0:#17         // #0:applyAsInt:()Ljava/util/function/ToIntFunction;
  #17 = NameAndType        #18:#19        // applyAsInt:()Ljava/util/function/ToIntFunction;
  #18 = Utf8               applyAsInt
  #19 = Utf8               ()Ljava/util/function/ToIntFunction;
  #20 = String             #21            //
  #21 = Utf8
  #22 = InterfaceMethodref #23.#25        // java/util/function/ToIntFunction.applyAsInt:(Ljava/lang/Object;)I
  #23 = Class              #24            // java/util/function/ToIntFunction
  #24 = Utf8               java/util/function/ToIntFunction
  #25 = NameAndType        #18:#26        // applyAsInt:(Ljava/lang/Object;)I
  #26 = Utf8               (Ljava/lang/Object;)I
  #27 = Utf8               args
  #28 = Utf8               [Ljava/lang/String;
  #29 = Utf8               f
  #30 = Utf8               Ljava/util/function/ToIntFunction;
  #31 = Utf8               LocalVariableTypeTable
  #32 = Utf8               Ljava/util/function/ToIntFunction<Ljava/lang/CharSequence;>;
  #33 = Utf8               MethodParameters
  #34 = Utf8               SourceFile
  #35 = Utf8               Temporary.java
  #36 = Utf8               BootstrapMethods
  #37 = Methodref          #38.#40        // 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;
  #38 = Class              #39            // java/lang/invoke/LambdaMetafactory
  #39 = Utf8               java/lang/invoke/LambdaMetafactory
  #40 = NameAndType        #41:#42        // 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;
  #41 = Utf8               metafactory
  #42 = 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;
  #43 = MethodHandle       6:#37          // 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;
  #44 = MethodType         #26            //  (Ljava/lang/Object;)I
  #45 = InterfaceMethodref #46.#48        // java/lang/CharSequence.length:()I
  #46 = Class              #47            // java/lang/CharSequence
  #47 = Utf8               java/lang/CharSequence
  #48 = NameAndType        #49:#50        // length:()I
  #49 = Utf8               length
  #50 = Utf8               ()I
  #51 = MethodHandle       9:#45          // REF_invokeInterface java/lang/CharSequence.length:()I
  #52 = Utf8               (Ljava/lang/CharSequence;)I
  #53 = MethodType         #52            //  (Ljava/lang/CharSequence;)I
  #54 = Utf8               InnerClasses
  #55 = Class              #56            // java/lang/invoke/MethodHandles$Lookup
  #56 = Utf8               java/lang/invoke/MethodHandles$Lookup
  #57 = Class              #58            // java/lang/invoke/MethodHandles
  #58 = Utf8               java/lang/invoke/MethodHandles
  #59 = Utf8               Lookup
{
  J();
    descriptor: ()V
    flags: (0x0000)
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LJ;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: invokedynamic #16,  0             // InvokeDynamic #0:applyAsInt:()Ljava/util/function/ToIntFunction;
         5: astore_1
         6: aload_1
         7: ldc           #20                 // String
         9: invokeinterface #22,  2           // InterfaceMethod java/util/function/ToIntFunction.applyAsInt:(Ljava/lang/Object;)I
        14: pop
        15: return
      LineNumberTable:
        line 5: 0
        line 6: 6
        line 25: 15
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      16     0  args   [Ljava/lang/String;
            6      10     1     f   Ljava/util/function/ToIntFunction;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            6      10     1     f   Ljava/util/function/ToIntFunction<Ljava/lang/CharSequence;>;
    MethodParameters:
      Name                           Flags
      args
}

BootstrapMethods:
  0: #43 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;
    Method arguments:
      #44 (Ljava/lang/Object;)I
      #51 REF_invokeInterface java/lang/CharSequence.length:()I
      #53 (Ljava/lang/CharSequence;)I
InnerClasses:
  public static final #59= #55 of #57;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
public class Groovy9853 implements groovy.lang.GroovyObject
  minor version: 0
  major version: 52
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #2                          // Groovy9853
  super_class: #4                         // java/lang/Object
  interfaces: 1, fields: 3, methods: 6, attributes: 2
Constant pool:
    #1 = Utf8               Groovy9853
    #2 = Class              #1            // Groovy9853
    #3 = Utf8               java/lang/Object
    #4 = Class              #3            // java/lang/Object
    #5 = Utf8               groovy/lang/GroovyObject
    #6 = Class              #5            // groovy/lang/GroovyObject
    #7 = Utf8               Scratch.groovy
    #8 = Utf8               $staticClassInfo
    #9 = Utf8               Lorg/codehaus/groovy/reflection/ClassInfo;
   #10 = Utf8               __$stMC
   #11 = Utf8               Z
   #12 = Utf8               metaClass
   #13 = Utf8               Lgroovy/lang/MetaClass;
   #14 = Utf8               <init>
   #15 = Utf8               ()V
   #16 = Utf8               Lgroovy/transform/Generated;
   #17 = NameAndType        #14:#15       // "<init>":()V
   #18 = Methodref          #4.#17        // java/lang/Object."<init>":()V
   #19 = Utf8               $getStaticMetaClass
   #20 = Utf8               ()Lgroovy/lang/MetaClass;
   #21 = NameAndType        #19:#20       // $getStaticMetaClass:()Lgroovy/lang/MetaClass;
   #22 = Methodref          #2.#21        // Groovy9853.$getStaticMetaClass:()Lgroovy/lang/MetaClass;
   #23 = NameAndType        #12:#13       // metaClass:Lgroovy/lang/MetaClass;
   #24 = Fieldref           #2.#23        // Groovy9853.metaClass:Lgroovy/lang/MetaClass;
   #25 = Utf8               this
   #26 = Utf8               LGroovy9853;
   #27 = Utf8               main
   #28 = Utf8               ([Ljava/lang/String;)V
   #29 = Utf8               args
   #30 = Utf8               (Ljava/lang/Object;)I
   #31 = MethodType         #30           //  (Ljava/lang/Object;)I
   #32 = Utf8               java/lang/CharSequence
   #33 = Class              #32           // java/lang/CharSequence
   #34 = Utf8               length
   #35 = Utf8               ()I
   #36 = NameAndType        #34:#35       // length:()I
   #37 = InterfaceMethodref #33.#36       // java/lang/CharSequence.length:()I
   #38 = MethodHandle       5:#37         // REF_invokeVirtual java/lang/CharSequence.length:()I
   #39 = Utf8               (Ljava/lang/CharSequence;)I
   #40 = MethodType         #39           //  (Ljava/lang/CharSequence;)I
   #41 = Utf8               java/lang/invoke/LambdaMetafactory
   #42 = Class              #41           // java/lang/invoke/LambdaMetafactory
   #43 = Utf8               metafactory
   #44 = 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;
   #45 = NameAndType        #43:#44       // 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;
   #46 = Methodref          #42.#45       // 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;
   #47 = MethodHandle       6:#46         // 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;
   #48 = Utf8               applyAsInt
   #49 = Utf8               ()Ljava/util/function/ToIntFunction;
   #50 = NameAndType        #48:#49       // applyAsInt:()Ljava/util/function/ToIntFunction;
   #51 = InvokeDynamic      #0:#50        // #0:applyAsInt:()Ljava/util/function/ToIntFunction;
   #52 = Utf8
   #53 = String             #52           //
   #54 = Utf8               java/util/function/ToIntFunction
   #55 = Class              #54           // java/util/function/ToIntFunction
   #56 = NameAndType        #48:#30       // applyAsInt:(Ljava/lang/Object;)I
   #57 = InterfaceMethodref #55.#56       // java/util/function/ToIntFunction.applyAsInt:(Ljava/lang/Object;)I
   #58 = Utf8               [Ljava/lang/String;
   #59 = Utf8               f
   #60 = Utf8               Ljava/util/function/ToIntFunction;
   #61 = Utf8               getClass
   #62 = Utf8               ()Ljava/lang/Class;
   #63 = NameAndType        #61:#62       // getClass:()Ljava/lang/Class;
   #64 = Methodref          #4.#63        // java/lang/Object.getClass:()Ljava/lang/Class;
   #65 = Utf8               org/codehaus/groovy/runtime/ScriptBytecodeAdapter
   #66 = Class              #65           // org/codehaus/groovy/runtime/ScriptBytecodeAdapter
   #67 = Utf8               initMetaClass
   #68 = Utf8               (Ljava/lang/Object;)Lgroovy/lang/MetaClass;
   #69 = NameAndType        #67:#68       // initMetaClass:(Ljava/lang/Object;)Lgroovy/lang/MetaClass;
   #70 = Methodref          #66.#69       // org/codehaus/groovy/runtime/ScriptBytecodeAdapter.initMetaClass:(Ljava/lang/Object;)Lgroovy/lang/MetaClass;
   #71 = NameAndType        #8:#9         // $staticClassInfo:Lorg/codehaus/groovy/reflection/ClassInfo;
   #72 = Fieldref           #2.#71        // Groovy9853.$staticClassInfo:Lorg/codehaus/groovy/reflection/ClassInfo;
   #73 = Utf8               org/codehaus/groovy/reflection/ClassInfo
   #74 = Class              #73           // org/codehaus/groovy/reflection/ClassInfo
   #75 = Utf8               getClassInfo
   #76 = Utf8               (Ljava/lang/Class;)Lorg/codehaus/groovy/reflection/ClassInfo;
   #77 = NameAndType        #75:#76       // getClassInfo:(Ljava/lang/Class;)Lorg/codehaus/groovy/reflection/ClassInfo;
   #78 = Methodref          #74.#77       // org/codehaus/groovy/reflection/ClassInfo.getClassInfo:(Ljava/lang/Class;)Lorg/codehaus/groovy/reflection/ClassInfo;
   #79 = Utf8               getMetaClass
   #80 = NameAndType        #79:#20       // getMetaClass:()Lgroovy/lang/MetaClass;
   #81 = Methodref          #74.#80       // org/codehaus/groovy/reflection/ClassInfo.getMetaClass:()Lgroovy/lang/MetaClass;
   #82 = Utf8               Lgroovy/transform/Internal;
   #83 = Utf8               Ljava/beans/Transient;
   #84 = Utf8               groovy/lang/MetaClass
   #85 = Class              #84           // groovy/lang/MetaClass
   #86 = Utf8               setMetaClass
   #87 = Utf8               (Lgroovy/lang/MetaClass;)V
   #88 = Utf8               mc
   #89 = Utf8               $getLookup
   #90 = Utf8               ()Ljava/lang/invoke/MethodHandles$Lookup;
   #91 = Utf8               java/lang/invoke/MethodHandles
   #92 = Class              #91           // java/lang/invoke/MethodHandles
   #93 = Utf8               lookup
   #94 = NameAndType        #93:#90       // lookup:()Ljava/lang/invoke/MethodHandles$Lookup;
   #95 = Methodref          #92.#94       // java/lang/invoke/MethodHandles.lookup:()Ljava/lang/invoke/MethodHandles$Lookup;
   #96 = Utf8               Code
   #97 = Utf8               LocalVariableTable
   #98 = Utf8               RuntimeVisibleAnnotations
   #99 = Utf8               LineNumberTable
  #100 = Utf8               MethodParameters
  #101 = Utf8               StackMapTable
  #102 = Utf8               SourceFile
  #103 = Utf8               BootstrapMethods
{
  private static org.codehaus.groovy.reflection.ClassInfo $staticClassInfo;
    descriptor: Lorg/codehaus/groovy/reflection/ClassInfo;
    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC

  public static transient boolean __$stMC;
    descriptor: Z
    flags: (0x1089) ACC_PUBLIC, ACC_STATIC, ACC_TRANSIENT, ACC_SYNTHETIC

  private transient groovy.lang.MetaClass metaClass;
    descriptor: Lgroovy/lang/MetaClass;
    flags: (0x1082) ACC_PRIVATE, ACC_TRANSIENT, ACC_SYNTHETIC

  public Groovy9853();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: aload_0
         1: invokespecial #18                 // Method java/lang/Object."<init>":()V
         4: aload_0
         5: invokevirtual #22                 // Method $getStaticMetaClass:()Lgroovy/lang/MetaClass;
         8: astore_1
         9: aload_1
        10: aload_0
        11: swap
        12: putfield      #24                 // Field metaClass:Lgroovy/lang/MetaClass;
        15: aload_1
        16: pop
        17: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      17     0  this   LGroovy9853;
    RuntimeVisibleAnnotations:
      0: #16()
        groovy.transform.Generated

  public static void main(java.lang.String...);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0089) ACC_PUBLIC, ACC_STATIC, ACC_VARARGS
    Code:
      stack=2, locals=2, args_size=1
         0: invokedynamic #51,  0             // InvokeDynamic #0:applyAsInt:()Ljava/util/function/ToIntFunction;
         5: astore_1
         6: aload_1
         7: pop
         8: aload_1
         9: ldc           #53                 // String
        11: invokeinterface #57,  2           // InterfaceMethod java/util/function/ToIntFunction.applyAsInt:(Ljava/lang/Object;)I
        16: pop
        17: return
      LineNumberTable:
        line 7: 0
        line 8: 8
        line 9: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      17     0  args   [Ljava/lang/String;
            6      11     1     f   Ljava/util/function/ToIntFunction;
    MethodParameters:
      Name                           Flags
      args

  protected groovy.lang.MetaClass $getStaticMetaClass();
    descriptor: ()Lgroovy/lang/MetaClass;
    flags: (0x1004) ACC_PROTECTED, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=1
         0: aload_0
         1: invokevirtual #64                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
         4: ldc           #2                  // class Groovy9853
         6: if_acmpeq     14
         9: aload_0
        10: invokestatic  #70                 // Method org/codehaus/groovy/runtime/ScriptBytecodeAdapter.initMetaClass:(Ljava/lang/Object;)Lgroovy/lang/MetaClass;
        13: areturn
        14: getstatic     #72                 // Field $staticClassInfo:Lorg/codehaus/groovy/reflection/ClassInfo;
        17: astore_1
        18: aload_1
        19: ifnonnull     34
        22: aload_0
        23: invokevirtual #64                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
        26: invokestatic  #78                 // Method org/codehaus/groovy/reflection/ClassInfo.getClassInfo:(Ljava/lang/Class;)Lorg/codehaus/groovy/reflection/ClassInfo;
        29: dup
        30: astore_1
        31: putstatic     #72                 // Field $staticClassInfo:Lorg/codehaus/groovy/reflection/ClassInfo;
        34: aload_1
        35: invokevirtual #81                 // Method org/codehaus/groovy/reflection/ClassInfo.getMetaClass:()Lgroovy/lang/MetaClass;
        38: areturn
      StackMapTable: number_of_entries = 2
        frame_type = 14 /* same */
        frame_type = 252 /* append */
          offset_delta = 19
          locals = [ class org/codehaus/groovy/reflection/ClassInfo ]

  public groovy.lang.MetaClass getMetaClass();
    descriptor: ()Lgroovy/lang/MetaClass;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: getfield      #24                 // Field metaClass:Lgroovy/lang/MetaClass;
         4: dup
         5: ifnull        9
         8: areturn
         9: pop
        10: aload_0
        11: dup
        12: invokevirtual #22                 // Method $getStaticMetaClass:()Lgroovy/lang/MetaClass;
        15: putfield      #24                 // Field metaClass:Lgroovy/lang/MetaClass;
        18: aload_0
        19: getfield      #24                 // Field metaClass:Lgroovy/lang/MetaClass;
        22: areturn
      StackMapTable: number_of_entries = 1
        frame_type = 73 /* same_locals_1_stack_item */
          stack = [ class groovy/lang/MetaClass ]
    RuntimeVisibleAnnotations:
      0: #16()
        groovy.transform.Generated
      1: #82()
        groovy.transform.Internal
      2: #83()
        java.beans.Transient

  public void setMetaClass(groovy.lang.MetaClass);
    descriptor: (Lgroovy/lang/MetaClass;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #24                 // Field metaClass:Lgroovy/lang/MetaClass;
         5: return
    RuntimeVisibleAnnotations:
      0: #16()
        groovy.transform.Generated
      1: #82()
        groovy.transform.Internal
    MethodParameters:
      Name                           Flags
      mc

  public static java.lang.invoke.MethodHandles$Lookup $getLookup();
    descriptor: ()Ljava/lang/invoke/MethodHandles$Lookup;
    flags: (0x1009) ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=1, locals=0, args_size=0
         0: invokestatic  #95                 // Method java/lang/invoke/MethodHandles.lookup:()Ljava/lang/invoke/MethodHandles$Lookup;
         3: areturn
}

BootstrapMethods:
  0: #47 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;
    Method arguments:
      #31 (Ljava/lang/Object;)I
      #38 REF_invokeVirtual java/lang/CharSequence.length:()I
      #40 (Ljava/lang/CharSequence;)I

你是对的,这是Groovy编译器的一个错误,由错误使用tagisInterface参数引起。

让我们从isInterface参数开始:

当且仅当所有者 class(也是 Handle 构造函数的参数)是一个接口时,此参数才为真。

让我们来看看一些Groovy's code:

default Handle createBootstrapMethod(boolean isInterface, boolean serializable) {
    if (serializable) {
        return new Handle(
                Opcodes.H_INVOKESTATIC,
                "java/lang/invoke/LambdaMetafactory",
                "altMetafactory",
                "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;",
                isInterface
        );
    }

    return new Handle(
            Opcodes.H_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;",
            isInterface
    );
}

(从 here 调用)

java.lang.invoke.LambdaMetafactory 不是接口。永远不会。
所以传递给 Handle 构造函数的正确的东西是常量 false.

接下来是handle for the target method itself:

 createBootstrapMethodArguments(createMethodDescriptor(abstractMethod), H_INVOKEVIRTUAL, lambdaClass, lambdaMethod, expression.isSerializable())

您要创建的句柄用于实现方法 - 通常是同一 class 中的私有方法。同样,如果所有者 class 是一个接口,isInterface 就是 true

您必须使用 H_* 常量,其名称与调用该方法的指令相似。

从设计的角度来看,可能有一个辅助方法可以将任何 MethodNode 转换为 Handle