Invoke dynamic support

Introduction

Since Groovy 2.0, support was added for the JVM invokedynamic instruction. This instruction is supported since Java 7 and is a bytecode instruction in the JVM that allows easier implementation of dynamic languages. This instruction is also used internally, by the JVM, for lambda support in Java 8+.

This feature is not visible to the developer or the end user. It is a compilation and runtime feature only. It affects how Groovy compiles dynamic method calls, property access, and other dynamic operations into bytecode.

Groovy 4.0+ (current)

From Groovy 4.0 onwards, invokedynamic bytecode generation is enabled by default. There is a single set of jars, compiled with invokedynamic enabled. The separate "-indy" jars and Maven classifiers from earlier versions are no longer needed.

It is still possible to disable invokedynamic for user-compiled code, which causes the compiler to fall back to classic call-site caching bytecode. This can be useful in cases where call-site caching is faster for specific workloads. To disable:

  • System property: groovy.target.indy=false
  • Compiler configuration: set the indy optimization option to false

Note that disabling invokedynamic only affects the bytecode generated for your code. The Groovy runtime jars themselves are compiled with invokedynamic enabled.

There are also internal thresholds that can be tuned for performance (search the codebase for groovy.indy.optimize.threshold and groovy.indy.fallback.threshold).

Groovy 2.0 to 3.x

Two JARs

The Groovy distribution came with two jars:

  • groovy-x.y.z.jar: compiled with classic call-site caching
  • groovy-x-y-z-indy.jar: compiled with invokedynamic

Both jars contained a fully working Groovy implementation capable of compiling user code using either invokedynamic or call-site caching. The sets of jars were mutually exclusive (don't put both on classpath) and the key difference was how the Groovy source files that make up Groovy itself were compiled.

When accessing a Groovy jar from a Maven repository, you could select the indy version using the 'indy' classifier.

The compilation flag

Independently of the jar version used, invokedynamic support required a specific compilation flag (indy). If you wanted to compile your classes with invokedynamic support, this flag had to be set at compile time.

For user compiled classes:

indy flagoffon
normal jarcall site cachinginvokedynamic
indy jarcall site cachinginvokedynamic

For core Groovy classes:

indy flagoffon
normal jarcall site cachingcall site caching
indy jarinvokedynamicinvokedynamic

So even if you used the indy jar, if you didn't use the invokedynamic flag at compile time, then the compiled classes would use the "old" format with call-site caching.