我正在尝试使用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语言构造可生成加载ldc
的MethodHandle
指令。不过,您可以使用更复杂的结构创建等效的句柄:
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
字节码指令更为复杂,而且还不得不处理已检查的异常NoSuchMethodException
和IllegalAccessException
(或它们的共同祖先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()
转换回从常量池加载ldc
的MethodHandle
指令。