Reputation: 2963
I'm currently writing a JVM in C# for purely academic purposes (and maybe to build a mixed .NET and Java/Scala application in the future).
I write the simple JAVA class:
public class test
{
public static String hello_world(int i)
{
return "Hello " + i + " World!";
}
}
And compile it into test.class
.
When I decompile it with my decompiler (which I have written as part of the JVM), I see the following instructions for this method:
iload_0
invokedynamic 2
areturn
When looking inside the constant pool for the constant at index 2
, I see an InvokeDynamic-Constant entry with the following data:
makeConcatWithConstants : (I)Ljava/lang/String;
Which makes sense, I guess (I am more a .NET-user than a JAVA-user).
When executing my method hello_world
with the parameter 1
, I have the following Stack before executing invokedynamic 2
:
----TOP---
0x00000001
--BOTTOM--
My question is: How do I use invokedynamic
?
I cannot resolve the method makeConcatWithConstants
, as the InvokeDynamic-Constant does not give me any hint, where makeConcatWithConstants
might be located (see documentation).
Neither does the stack contain a reference to the heap, indicating which instance type the method makeConcatWithConstants
could be associated with.
I read through the invokedynamic
docs but I do not understand it (Maybe I'm to much "damaged" by the .NET-Framework).
Can somebody point me to some example about what is going on under the JVM's hood when executing these three instructions? (What the callee of invokedynamic
expects etc.)?
I already implemented invokestatic
in my JVM ... but I am currently unable to understand invokedynamic
.
Upvotes: 2
Views: 2309
Reputation: 33885
The idea of invokedynamic
is; When first encountering this bytecode call a bootstrap method which creates a Callsite
object that links to the actual method that needs to be invoked.
In practice this often means that you dynamically create the implementation for the call.
If you look at your program with javap -v test
, you will see at the bottom a BootstrapMethods
attribute:
BootstrapMethods:
0: #15 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
Method arguments:
#16 Hello \u0001 World!
Where you can see that the bootstrap method for this particular callsite is located in StringConcatFactory
The Method arguments
are the set of constant arguments.
The leading arguments of Lookup
, String
and MethodType
are respectively; a lookup object with the same priveledges as the callsite, some name, and the type of the callsite. The first of these needs to be provided by the VM at runtime , and the latter 2 are provided by the invokedynamic constant pool entry in the form of a name and type:
#2 = InvokeDynamic #0:#17 // #0:makeConcatWithConstants:(I)Ljava/lang/String;
So to implement this bytecode you have to have some machinery in place to create the lookup object, and then be able to call the bootstrap method. After that you can call dynamicInvoker()
on the returned Callsite
object, which gives you a MethodHandle
that you should then cache for this particular callsite and then (finally) invoke.
If you want to look at how this is implemented in OpenJDK you can find the implementation here: http://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/interpreter/bytecodeInterpreter.cpp#l2446
I'm guessing this is probably too tricky at this early stage of the project, so for now it might be easier to compile your program with -XDstringConcat=inline
, since that uses the legacy StringBuilder
concatenation, which should be simpler to implement.
Upvotes: 5