Using "invokedynamic" - What is going on under the hood?

2k views Asked by At

Background

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).

Context

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--

Question

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.

1

There are 1 answers

3
Jorn Vernee On BEST ANSWER

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.