我正在尝试使用Java 8 Nashorn和完整的源代码(未检测)。如您所知,它使用Nasgen修改.classes,输出以JRE/lib/ext/nashorn.jar交付。

在分解输出时,使用javap:

 0: aload_0
 1: ldc           #24                 // String Function
 3: ldc           #31                 // MethodHandle invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;
 5: getstatic     #22                 // Field $nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap;
 8: aconst_null
 9: invokespecial #34                 // Method jdk/nashorn/internal/objects/ScriptFunctionImpl."<init>":(Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V

可能会错误地写为
super("Function", NativeFunction.function, $nasgenmap$, (Specialization[]) null);

,应使用签名调用超级构造函数:
ScriptFunctionImpl(String, MethodHandle, PropertyMap, Specialization[]) { }

我的问题是第二个参数NativeFunction.function(我没有一个可编译的源),以便在常量池中生成相同的MethodHandle
  #31 = MethodHandle       #6:#30         //  invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;

该部分检测是由ASM通过调用MethodVisitor.visitLdcInsn完成的。

那么,是否有一种方法可以从Java源代码构造这种方法句柄,或者这是只能在字节码级别完成的功能?

完整的javap输出:
$javap -c -v NativeFunction$Constructor.class

  Last modified Apr 10, 2015; size 1161 bytes
  MD5 checksum dcae2f54643befc519a45e9ac9bc4781
final class jdk.nashorn.internal.objects.NativeFunction$Constructor extends jdk.nashorn.internal.objects.ScriptFunctionImpl
  minor version: 0
  major version: 51
  flags: ACC_FINAL
Constant pool:
   #1 = Utf8               jdk/nashorn/internal/objects/NativeFunction$Constructor
   #2 = Class              #1             //  jdk/nashorn/internal/objects/NativeFunction$Constructor
   #3 = Utf8               jdk/nashorn/internal/objects/ScriptFunctionImpl
   #4 = Class              #3             //  jdk/nashorn/internal/objects/ScriptFunctionImpl
   #5 = Utf8               $nasgenmap$
   #6 = Utf8               Ljdk/nashorn/internal/runtime/PropertyMap;
   #7 = Utf8               <clinit>
   #8 = Utf8               ()V
   #9 = Utf8               java/util/ArrayList
  #10 = Class              #9             //  java/util/ArrayList
  #11 = Utf8               <init>
  #12 = Utf8               (I)V
  #13 = NameAndType        #11:#12        //  "<init>":(I)V
  #14 = Methodref          #10.#13        //  java/util/ArrayList."<init>":(I)V
  #15 = Utf8               jdk/nashorn/internal/runtime/PropertyMap
  #16 = Class              #15            //  jdk/nashorn/internal/runtime/PropertyMap
  #17 = Utf8               newMap
  #18 = Utf8               (Ljava/util/Collection;)Ljdk/nashorn/internal/runtime/PropertyMap;
  #19 = NameAndType        #17:#18        //  newMap:(Ljava/util/Collection;)Ljdk/nashorn/internal/runtime/PropertyMap;
  #20 = Methodref          #16.#19        //  jdk/nashorn/internal/runtime/PropertyMap.newMap:(Ljava/util/Collection;)Ljdk/nashorn/internal/runtime/PropertyMap;
  #21 = NameAndType        #5:#6          //  $nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap;
  #22 = Fieldref           #2.#21         //  jdk/nashorn/internal/objects/NativeFunction$Constructor.$nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap;
  #23 = Utf8               Function
  #24 = String             #23            //  Function
  #25 = Utf8               jdk/nashorn/internal/objects/NativeFunction
  #26 = Class              #25            //  jdk/nashorn/internal/objects/NativeFunction
  #27 = Utf8               function
  #28 = Utf8               (ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;
  #29 = NameAndType        #27:#28        //  function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;
  #30 = Methodref          #26.#29        //  jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;
  #31 = MethodHandle       #6:#30         //  invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;
  #32 = Utf8               (Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V
  #33 = NameAndType        #11:#32        //  "<init>":(Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V
  #34 = Methodref          #4.#33         //  jdk/nashorn/internal/objects/ScriptFunctionImpl."<init>":(Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V
  #35 = Utf8               jdk/nashorn/internal/objects/NativeFunction$Prototype
  #36 = Class              #35            //  jdk/nashorn/internal/objects/NativeFunction$Prototype
  #37 = NameAndType        #11:#8         //  "<init>":()V
  #38 = Methodref          #36.#37        //  jdk/nashorn/internal/objects/NativeFunction$Prototype."<init>":()V
  #39 = Utf8               jdk/nashorn/internal/objects/PrototypeObject
  #40 = Class              #39            //  jdk/nashorn/internal/objects/PrototypeObject
  #41 = Utf8               setConstructor
  #42 = Utf8               (Ljava/lang/Object;Ljava/lang/Object;)V
  #43 = NameAndType        #41:#42        //  setConstructor:(Ljava/lang/Object;Ljava/lang/Object;)V
  #44 = Methodref          #40.#43        //  jdk/nashorn/internal/objects/PrototypeObject.setConstructor:(Ljava/lang/Object;Ljava/lang/Object;)V
  #45 = Utf8               jdk/nashorn/internal/runtime/ScriptFunction
  #46 = Class              #45            //  jdk/nashorn/internal/runtime/ScriptFunction
  #47 = Utf8               setPrototype
  #48 = Utf8               (Ljava/lang/Object;)V
  #49 = NameAndType        #47:#48        //  setPrototype:(Ljava/lang/Object;)V
  #50 = Methodref          #46.#49        //  jdk/nashorn/internal/runtime/ScriptFunction.setPrototype:(Ljava/lang/Object;)V
  #51 = Utf8               setArity
  #52 = NameAndType        #51:#12        //  setArity:(I)V
  #53 = Methodref          #46.#52        //  jdk/nashorn/internal/runtime/ScriptFunction.setArity:(I)V
  #54 = Utf8               Code
{
  public static {};
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=0, args_size=0
         0: new           #10                 // class java/util/ArrayList
         3: dup
         4: iconst_1
         5: invokespecial #14                 // Method java/util/ArrayList."<init>":(I)V
         8: invokestatic  #20                 // Method jdk/nashorn/internal/runtime/PropertyMap.newMap:(Ljava/util/Collection;)Ljdk/nashorn
/internal/runtime/PropertyMap;
        11: putstatic     #22                 // Field $nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap;
        14: return

  jdk.nashorn.internal.objects.NativeFunction$Constructor();
    flags:
    Code:
      stack=5, locals=1, args_size=1
         0: aload_0
         1: ldc           #24                 // String Function
         3: ldc           #31                 // MethodHandle invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;
         5: getstatic     #22                 // Field $nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap;
         8: aconst_null
         9: invokespecial #34                 // Method jdk/nashorn/internal/objects/ScriptFunctionImpl."<init>":(Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V
        12: aload_0
        13: new           #36                 // class jdk/nashorn/internal/objects/NativeFunction$Prototype
        16: dup
        17: invokespecial #38                 // Method jdk/nashorn/internal/objects/NativeFunction$Prototype."<init>":()V
        20: dup
        21: aload_0
        22: invokestatic  #44                 // Method jdk/nashorn/internal/objects/PrototypeObject.setConstructor:(Ljava/lang/Object;Ljava/lang/Object;)V
        25: invokevirtual #50                 // Method jdk/nashorn/internal/runtime/ScriptFunction.setPrototype:(Ljava/lang/Object;)V
        28: aload_0
        29: iconst_1
        30: invokevirtual #53                 // Method jdk/nashorn/internal/runtime/ScriptFunction.setArity:(I)V
        33: return
}

最佳答案

没有Java语言构造可生成加载ldcMethodHandle指令。不过,您可以使用更复杂的结构创建等效的句柄:

MethodHandles.lookup().findStatic(
  jdk.nashorn.internal.objects.NativeFunction.class, "function",
  MethodType.fromMethodDescriptorString(
   "(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;",
   null))

这不仅比单个ldc字节码指令更为复杂,而且还不得不处理已检查的异常NoSuchMethodExceptionIllegalAccessException(或它们的共同祖先ReflectiveOperationException)。

您可以将操作封装为类似
private static MethodHandle MH_NativeFunction_function() {
  try {
    return MethodHandles.lookup().findStatic(
      jdk.nashorn.internal.objects.NativeFunction.class, "function",
      MethodType.fromMethodDescriptorString("(ZLjava/lang/Object;[Ljava/lang/Object;)"
        + "Ljdk/nashorn/internal/runtime/ScriptFunction;", null));
  } catch(ReflectiveOperationException ex) {
      throw new AssertionError(ex);
  }
}

并在您的构造函数中将其称为
super("Function", MH_NativeFunction_function(), $nasgenmap$, (Specialization[]) null);

这种方法的优势在于,您可以使用 Indify 将调用MH_NativeFunction_function()转换回从常量池加载ldcMethodHandle指令。

07-26 02:58