I am trying to have Java 8 Nashorn with complete source (not instrumented). As you may know, it uses Nasgen to modify the .classes, and the output is shipped in JRE/lib/ext/nashorn.jar
.
On disassembling the output, using 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 could be erroneously written as
super("Function", NativeFunction.function, $nasgenmap$, (Specialization[]) null);
, which should call the super constructor with signature:
ScriptFunctionImpl(String, MethodHandle, PropertyMap, Specialization[]) { }
My issue is the second parameter NativeFunction.function
, which I couldn't have a compilable 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;
That part of instrumentation was done by ASM, by calling MethodVisitor.visitLdcInsn.
So, is there a way to construct such a method handle from the Java source, or this is a feature which can be done at bytecode-level only?
The 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
}
There is no Java language construct to produce an ldc
instruction loading a MethodHandle
. Still, you can create an equivalent handle with a more complicated 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 complicated than a single ldc
bytecode instruction, you are also forced to deal with the checked exceptions NoSuchMethodException
and IllegalAccessException
(or their common ancestor ReflectiveOperationException
).
You may encapsulate the operation into a method like
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 call it in you constructor as
super("Function", MH_NativeFunction_function(), $nasgenmap$, (Specialization[]) null);
the advantage of this approach is that you can use Indify
to convert the invocation MH_NativeFunction_function()
back to an ldc
instruction loading the MethodHandle
from the constant pool.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With