invokedynamic
, a new bytecode instruction on the JVM for method invocation. The invokedynamic
instruction allows dynamic linkage between a call site and the receiver of the call. That means you can link the class that is performing a method call to the class (and method) that is receiving the call at run-time. All the other JVM bytecode instructions for method invocation, like invokevirtual
, hard-wire the target type information into your compilation, i.e. into your class file. Let's look at an example. The bytecode snippet above shows an
invokevirtual
method call of java.lang.String -> length()
in line 20. It refers to item 65 in the contsant pool table which is a MethodRef
entry (see line 6). Items 42 and 66 in the constant pool table refer to the class and the method descriptor entries. As you can see, the target type and method of the invokevirtual
call is completely resolved and hard-wired into the bytecode. Now, let's return to invokedynamic
!It is important to notice that it is not possible to compile Java code into bytecode that contains an
invokedynamic
instruction. Java is statically typed. That means that Java performs type checking at compile time. Therefore, in Java, it is possible (and wanted!) to hard-wire all type information of method call receivers into the callers class file. The caller knows the type name of the call target, as demonstrated in our example above. The use of invokedynamic
- on the other hand - enables the JVM to resolve exactly that type information at run-time. This is only required (and wanted!) for dynamic languages, such as JRuby or Rhino. Now, suppose you want to implement a new language on the JVM that is dynamically typed. I am not suggesting you should invent *another* language on the JVM, but *suppose* you would, and *suppose* your new language should be dynamically typed. That would mean, in your new language, the linking between a caller and a receiver of a method call is performed at run-time. Since Java 7 this is possible on the bytecode level using the
invokedynamic
instruction. Because I cannot create an
invokedynamic
instruction using a Java compiler, I will create a class file that contains invokedynamic
myself. Once this class file is created I will run that class file's main
method using an ordinary java
launcher. How can you create a class file without a compiler? This is possible by using bytecode manipulation frameworks like ASM or Javassist.The following code snippet shows the
SimpleDynamicInvokerGenerator
that can generate a class file SimpleDynamicInvoker.class
which contains an invokedynamic instruction.I am using ASM here, an all purpose Java bytecode manipulation and analysis framework, to do the job of creating a correct class file format. In line 30 the
visitInvokeDynamicInsn
creates the invokedynamic
instruction. Generating a class that does an invokedynamic
call is only half of the story. You also need some code that links the dynamic call site to the actual target, this is the real purpose of invokedynamic
. Here is an example.The bootstrap method in line 9-14 selects the actual target of the dynamic call. In our case the target is the
sayHello()
method. To learn how the bootstrap method is linked to the invokedynamic
instruction we need to dive into the bytecode of SimpleDynamicInvoker
that we've generated with SimpleDynamicInvokerGenerator
. In line 49 you can see the
invokedynamic
instruction. The logical name of the dynamic method is runCalculation
, this is a fictitious name. You can use any name that makes sense, also names like "+" are allowed. The instruction refers to item 20 in the contant pool table (see line 33). This in turn refers to index 0 in the BootstrapMethods
attribute (see line 8). There you can see the link to the SimpleDynamicLinkageExample.bootstrapDynamic
method that links the invokedynamic
instruction to the call target.Now if you call the
SimpleDynamicInvoker
using the java
launcher, then the invokedynamic
call is executed.The following sequence diagram illustrates what's happening when the
SimpleDynamicInvoker
is called using the java
launcher.The first call of
runCalculation
using invokedynamic
issues a call to the bootstrapDynamic
method. This method does the dynamic linkage between the calling class (SimpleDynamicInvoker
) and the receiving class (SimpleDynamicLinkageExample
). The bootstrap method returns a MethodHandle
that targets the receiving class. This method handle is cached for repetitive invocations of the runCalculation
method.That's all in terms of
invokedynamic
. I have some more sophisticated examples published here in my Git repo. I hope you've enjoyed reading this - in times of shortage!Cheers, Niklas
References:
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html
http://asm.ow2.org/
http://java.sun.com/developer/technicalArticles/DynTypeLang/
http://asm.ow2.org/doc/tutorial-asm-2.0.html
http://weblogs.java.net/blog/forax/archive/2011/01/07/calling-invokedynamic-java
http://nerds-central.blogspot.com/2011/05/performing-dynamicinvoke-from-java-step.html
Very good post on invokedynamic, keep them coming!
ReplyDeleteGreat article. Will try it in the weekend.
ReplyDeleteThis seems to be very powerful feature given its ability to support dynamic language thanks for posting this in detail as always.
ReplyDeleteJavin
String in Switch in JDK7 uses hashCode
Hi Niklas,
ReplyDeleteThanks for this post. I didn't know about this before reading this article. Please let me know if i can add some of your post in my website.
http://www.javabeginnerstutorial.com/
Thanks
Very Good Article..
ReplyDeleteCan I use it in spring-mvc?
I want to use it...
i got a parameter that Class name and Method name..
i want to find that method(Class and Method name)..
and Run it..
Thx for the comment. You cannot use it at all from within ordinary Java. The javac compiler will not generate an invokedynamic instruction. So, I suggest you'll use reflection instead?
DeleteCheers, Niklas
thx for you suggest :-)
ReplyDeleteperhaps i'm being dense, but where are MethodType, CallSite and MethodHandles defined? I'd assume asm 4 but don't see them.
ReplyDeleteMethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
Hello Niklas,
ReplyDeleteI just stumbled upon your blog - thank you very much for your interesting articles :)
I think that your statement "It is important to notice that it is not possible to compile Java code into bytecode that contains an invokedynamic instruction."
doesn't apply anymore if you take Java 8 into account. In Java 8 Lambda Expressions make use of the invokedynamic bytecode instruction.
If one compiles the following program with Java 8 javac (with an lambda enabled build (e.g. b75+)):
package de.tutorials.training.dynamic;
import java.util.function.Consumer;
public class LambdaInvokeDynamicExample {
public static void main(String[] args) {
Consumer c = (s) -> System.out.println(s);
c.accept("Hello InvokeDynamic!");
}
}
You get the following bytecode:
(Notice the bytecode instruction in main(...) at position 0 :)
C:\development\workspaces\intellij\de.tutorials.training\target\classes\de\tutorials\training\dynamic>%JAVA_HOME%\bin\javap -c LambdaInvokeDynamicExample.class
Compiled from "LambdaInvokeDynamicExample.java"
public class de.tutorials.training.dynamic.LambdaInvokeDynamicExample {
public de.tutorials.training.dynamic.LambdaInvokeDynamicExample();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokedynamic #2, 0 // InvokeDynamic #0:lambda$:()Ljava/util/function/Consumer;
5: astore_1
6: aload_1
7: ldc #3 // String Hello InvokeDynamic!
9: invokeinterface #4, 2 // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V
14: return
}
Best regards,
Thomas
REllay interesting tutorials of JAVA!
ReplyDeletethx!
ReplyDelete