//////////////////////////////////////////

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, either express or implied.  See the License for the
  specific language governing permissions and limitations
  under the License.

//////////////////////////////////////////

= InvokeDynamic support


== Foreword

Since Groovy 2.0, we added support for the JVM http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html#invokedynamic[invokedynamic] instruction. This instruction is supported since Java 7 and is a new bytecode instruction in the JVM that allows easier implementation of dynamic languages. This instruction will also be used internally, by the JVM, for the lambda support in Java 8.

This means that unlike APIs, AST transformations or syntactic sugar, this feature is **not visible** to the developer or the end user. It is a compilation and runtime feature only. This means that given two programs written in Groovy, you have the choice to compile it with or without invokedynamic support. Whatever you choose, it comes with pros and cons:

- classes compiled with invokedynamic can only be used on JDK 1.7+ (without invokedynamic, Groovy classes are still compatible with JDK 1.5+)
- call site caching, as implemented in "normal" Groovy is replaced with invokedynamic since Groovy 2.1
- it is possible to mix classes compiled with and without invokedynamic in the same project, as long as you run JDK 1.7+
- depending on the JVM (even different minor versions of the JVM), you can target close to Java performance for dynamic Groovy with invokedynamic support activated

== The distributions

=== Two jars

The Groovy distribution comes with **two** jars:

- groovy-x.y.z.jar : compatible with JDK 1.5+, makes use of call site caching
- groovy-x-y-z-indy.jar : compatible with JDK 1.7+ only, has invokedynamic support bundled, old call site caching still possible

The first jar is Groovy compiled without invokedynamic support, while the second one has invokedynamic support bundled. As Groovy core and the groovy modules are sometimes written in Groovy, we currently have no choice but issuing two distinct versions of Groovy. This means that if you pick the "normal" jar, the groovy classes of groovy itself are compiled with call site caching (1.5+), while if you use the "indy" jar, the groovy classes of groovy itself are compiled using invokedynamic. This means that the invokedynamic version of Groovy doesn't make use of the old call site caching mechanism.

Both jars contain a fully working groovy implementation. They are mutually exclusive (don't put both on classpath).

=== Command-line and indy
If you download the distribution and that you use the command line, it's always the "normal" version of Groovy which is picked up in classpath. This means that whatever command you use (`groovy`, `groovyc`, `groovysh` or `groovyConsole`), invokedynamic support is not available out of the box. To use the invokedynamic version, you have to switch the jars manually. The distribution makes use of the jars in the ++lib++ directory, while the indy jars are available in the ++indy++ directory. You have three things to do:

- remove or rename the groovy-*.jar files in the lib directory
- replace them with the indy version from the indy directory
- remove the -indy classifier from jar names

Here's a bash script that would do it all at once:

[source,bash]
----
$ for f in `ls lib/groovy*.jar | cut -d/ -f2`;do k=`basename $f .jar`; mv lib/$k.jar lib/$k.jar.old; cp indy/$k-indy.jar lib/$k.jar ; done
----

== The compilation flag

Independently of the jar version that you use (and after having exchanged the jars as described), invokedynamic support requires a specific compilation flag (__indy__). If you want to compile your classes with invokedynamic support, this flag must be set at compile time. The following tables show you what happens with user compiled classes and groovy core classes depending on the jar you use and the compilation flag:

[cols="1,1,1" options="header"]
.user compiled classes
|===
|indy flag
|**off**
|**on**

|normal jar
|call site caching
|N/A

|indy jar
|call site caching
|invokedynamic
|===

[cols="1,1,1" options="header"]
.core groovy classes
|===
|indy flag
|**off**
|**on**

|normal jar
|call site caching
|N/A

|indy jar
|invokedynamic
|invokedynamic
|===

So even if you use the indy jar, if you don't use the invokedynamic flag at compile time, then the compiled classes will use the "old" format, meaning they will use the JDK1.5+ classes without invokedynamic.