Java code to compile in MethodHandle in a persistent pool


I am trying to use Java 8 Nashorn with full source code (no tools). As you may know, it uses Nasgen to modify .classes, and the output is sent to JRE/lib/ext/nashorn.jar .


When javap output, use 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 

which may be mistakenly written as

 super("Function", NativeFunction.function, $nasgenmap$, (Specialization[]) null); 

which should call a super constructor with a signature:

 ScriptFunctionImpl(String, MethodHandle, PropertyMap, Specialization[]) { } 



My problem is the second parameter NativeFunction.function , which I could not have a compiled source to generate the same MethodHandle in the constant pool,

  #31 = MethodHandle #6:#30 // invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction; 

This part of the toolkit was done by ASM by calling MethodVisitor.visitLdcInsn .

So, is there a way to create such a method descriptor from a Java source, or is it a function that can only be executed at the bytecode level?

Full javap output:

 $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 } 
+6
source share
1 answer

There is no Java language construct to create an ldc statement loading a MethodHandle . However, you can create an equivalent descriptor with a more complex construct:

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

Not only is this more complex than a single ldc bytecode instruction, you also have to deal with checked NoSuchMethodException and IllegalAccessException (or their common ancestor ReflectiveOperationException ).

You can encapsulate an operation in a method of type

 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); } } 

and name it in your constructor as

 super("Function", MH_NativeFunction_function(), $nasgenmap$, (Specialization[]) null); 

The advantage of this approach is that you can use Indify to convert the call to MH_NativeFunction_function() back to the ldc , loading MethodHandle from the constant pool.

+6
source

Source: https://habr.com/ru/post/989229/


All Articles