This is eighth part of mini-series of Explaining invokedynamic. This is the full list of all articles:
Number multiplication (almost) complete example. Part IV
Dynamical hashCode implementation. Part V
Final notes
There is one detail that I didn’t cover: how bootstrap method is registered? You can write some Java method with correct signature, but how it will be used? The short answer: there is no API for registering bootstrap method.
Let’s go back to Java 7. invokedynamic
was designed back than to other (dynamic) language that runs on JVM. It wasn’t originally designed for Java Language. invokedynamic
is part Java Platform, not the Java Language.
Every language has it’s own compiler. So, such bootstrap has to be registered in such compiler. That compiler, than will emit invokedynamic
bytecode instruction, as it did with any other instruction. This instruction will link to bootstrap method on bytecode level. You can even write bootstrap method on your own language, as far it compiles to JVM bytecode, it can be used as bootstrap method.
I want to emphasize this point again. On Java 7 there were no language construct that will be implemented using invokedynamic.
So, all resources (at least what I’ve see) use one of two approaches:
- All example was in
bytecode.
So, you have to readbytecode
in order to understand new concept. - Java code use some Java library to emit the
bytecode
first and than looks onbytecode.
In such a way you see some high level construct, so this should easier your understanding ofbytecode.
Specifically, ASM or Javassist was popular. AFAIK, this is too low level. You can look on such example here http://niklasschlimm.blogspot.com/2012/02/java-7-complete-invokedynamic-example.html
Than, in Java 8 invokedynamic
was decided to be used to implement Lambda expressions. So, javac
was changed to recognized new syntax. javac
was “teached” to use specific method from the JDK as bootstrap method.
In next version of Java, when invokedynamic
the same process of “teaching” java compiler for bootstrap method and when it should be used was done. Bootstrap method was made also non-public to avoid dependence on it’s implementation details.
Now, I want to go over entirety post again to reveal it’s internal structure.
- It starts with
invokestatic
andinvokevirtual
bytecode in order to give you some idea what bytecode is and how it is used. This part is high level and should be easy to grasp to anybody who uses Java. - Than there is separate section with concrete code examples that show you what is
MethodHandle
&CallSite
&MethodHandles.Lookup.
This part focuses on API usage and enriches your vocabulary, you’re learning concepts that are not well-known. It use following weird construct to triggerinvokevirtual:
example.createCallSite(“DOG”).dynamicInvoker().invoke(example)
- Than I’m giving your another concrete and (almost) complete code examples that is fully written in Java and with limitation of absence of code construct in Java that will trigger
invokevirtual.
It uses following construct:
DYNAMIC1.multiply(bigNum, bigNum)
that is also weired, but resembles pretty close the real usage.
When you read this example, you should fill comfortable with both language that is used and the API that should be at least somewhat familiar for you at this point.
Than the “real” examples are
- Simplified String concatenation. This is pretty simple and it demonstrates the full power of bootstrap method in practice. I’m deliberately not showing the actual implementation code here.
- Simplified Lambda
I want just to “make an reduction” to the previous case. I’m mentioning all important parts of Lambda expressions without going to almost any detail. I’m given only simple Lambda expressions example. I’m deliberately not showing the actual implementation code here.
- Records
This is the shortest example section. I’m given link to my existed article for broader explanation (I will give more broader explanation sometimes). For the implementation details you can read Dynamical hashCode implementation. Part V (you will find their implementation also toString
and equals
methods).
Let’s look on how invokedynamic
works diagram again.
As I’ve described above, the first part of generating invokedynamic
is not well supported in Java. In my “toy” examples some weird construct was used to overcome this limitation.
My “toy” example embeds Implementation logic as static Java code.
Lambda metafactory and StringConcatFactory.makeConcatWithConstants (and theire variants) uses some JDK internal API that is similar to ASM. I will not provide it here.
In the real world example, this code is actually generated in runtime by bootsrap method itself. For the “real word” example it is better to look on Dynamical hashCode implementation. Part V This chapter provides implementation details for the Records — preview feature of JDK 14.
This is eighth part of mini-series of Explaining invokedynamic. This is the full list of all articles:
Number multiplication (almost) complete example. Part IV
Dynamical hashCode implementation. Part V