I'm working with Java bytecode via ASM and am trying to get a simple invokedynamic
example functioning properly. I feel as though I'm fundamentally misunderstanding how invokedynamic is supposed to work. This is what I've tried so far:
In Test2.java
I have a static method I wish to invoke and my bootstrap method:
public static int plus(int a, int b) { // method I want to dynamically invoke
return a + b;
}
public static CallSite bootstrap(MethodHandles.Lookup caller, String name,
MethodType type) throws Exception {
MethodHandle mh = MethodHandles.lookup().findStatic(Test2.class,
"plus", MethodType.methodType(int.class, int.class, int.class));
return new ConstantCallSite(mh);
}
Now, in Test.java
I generate a class file called Example.class
in a package package1
with ASM:
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",
"([Ljava/lang/String;)V", null, null);
mv.visitCode();
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
"Ljava/io/PrintStream;");
mv.visitIntInsn(BIPUSH, 42);
mv.visitIntInsn(BIPUSH, 24);
// mv.visitMethodInsn(INVOKESTATIC, "package1/Test2", "plus", "(II)I");
MethodType mt = MethodType.methodType(CallSite.class,
MethodHandles.Lookup.class, String.class, MethodType.class);
Handle bootstrap = new Handle(Opcodes.INVOKESTATIC, "package1/Test2",
"bootstrap", mt.toMethodDescriptorString());
mv.visitInvokeDynamicInsn("plus", "(II)I", bootstrap, new Object[0]);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
"(I)V");
mv.visitInsn(RETURN);
However, when I try to run the generated class file, I receive the following:
Exception in thread "main" java.lang.ClassFormatError: Bad method handle kind at constant pool index 23 in class file package1/Example at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:792) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) at java.net.URLClassLoader.access$100(URLClassLoader.java:71) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
Replacing the invokedynamic
call with the usual invokestatic
call (the commented line above) yields the expected result. From the error message it seems to me that the Handle
representing my bootstrap method (bootstrap
) is not formed properly, but I cannot say for certain. Any help would be much appreciated. I'm using ASM 4.1.
You're passing in an opcode rather than a handle type as the handle type. Since they're both just ints, there's no type error, but you're providing garbage values which cause a verification error at load time.
You probably meant to do something like this (note the H_ prefix)
Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, "package1/Test2",
"bootstrap", mt.toMethodDescriptorString());
See here for the Handle documentation.
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