Java Reference
In-Depth Information
The invokedynamic instruction
The bytecode instruction invokedynamic was introduced in JDK7 to support dynamically typed
languages on the JVM. invokedynamic adds a further level of indirection when invoking a
method, to let some logic dependent on the specific dynamic language determine the call target.
The typical use for this instruction is something like the following:
def add(a, b) { a + b }
Here the types of a and b aren't known at compile time and can change from time to time. For
this reason, when the JVM executes an invokedynamic for the first time, it consults a bootstrap
method, implementing the language-dependent logic that determines the actual method to be
called. The bootstrap method returns a linked call site. There's a good chance that if the add
method is called with two ints, the subsequent call will also be with two ints. As a result, it's not
necessary to rediscover the method to be called at each invocation. The call site itself can
contain the logic defining under which conditions it needs to be relinked.
In listing D.2 , the features of the invokedynamic instruction have been used for a slightly
different purpose than the one for which they were originally introduced. In fact, here it's used
to delay the strategy used to translate lambda expressions in bytecode until runtime. In other
words, using invokedynamic in this way allows deferring code generation for implementing the
lambda expression until runtime. This design choice has positive consequences:
The strategy used to translate the lambda expression body to bytecode becomes a pure
implementation detail. It could also be changed dynamically, or optimized and modified in future
JVM implementations, preserving the bytecode's backward compatibility.
There's no overhead, such as additional fields or static initializer, if the lambda is never used.
For stateless (noncapturing) lambdas it's possible to create one instance of the lambda object, cache it,
and always return the same. This is a common use case, and people were used to doing this explicitly
before Java 8; for example, declaring a specific Comparator instance in a static final variable.
There's no additional performance cost because this translation has to be performed, and its result
linked, only when the lambda is invoked for the first time. All subsequent invocations can skip this
slow path and call the formerly linked implementation.
Search WWH ::




Custom Search