Implementing just-in-time compiler is a proper way to help boosting performance of Groovy. It would be great to have a Groovy module (in this case a JVMTI agent) to help re-compiling transform/redefine Groovy classes during runtime.
GJIT could be thought as a hotspot compiler for Groovy.
There are two main components.
The first one is a JVMTI agent to profile calls to
ScriptBytecodeAdapter.invoke* at the caller sites. The profiler then
gathers information, including Type information, from
MetaClassImpl.getMethod* to identify hot regions, with a threshold
After the threshold is reached the profiler tell the optimiser thread,
the second component, to perform dataflow analysis on these hot
regions, by replacing calls to ScriptBytecodeAdapter.invoke with
direct calls (to bypass the meta-layer). Classes then re-compiled and
re-defined using the JVMTI instrumentation. (no new class created, so
PermGen not affected)
There's also a hook to detect the change of meta-class of each class.
If there's a change, the optimiser will re-store the original class
and start profiling it again.
As of Groovy 1.6-beta series, the most performance problem is occurred from primitive calculation. All operand and results are heavily boxed and unboxed during these operations. The current implementation of GJIT provides the algorithm to unwrap almost binary operations back to be primitive. Thus, it can speed Groovy performance up when dealing with arithmetic calculation.
This is the completely re-written version of GJIT. Basically, GJIT can be thought as a Hotspot-like compiler for Groovy. However it is working outside JVM, and not a part of the virtual machine. GJIT uses JVMTI, the virtual machine tool interface, to:
- Transform a class when it is being loaded, based on the assumption that the default metaclass provides the default behaviour.
- Redefine the class with the original one, when the metaclass of this class is modified.
Due to the use of JVMTI, GJIT supports Java 5 or later.
to your Java command line to use GJIT.
Missing Features and Known Bugs
- GJIT's optimiser thread will not stop by itself. You have to kill the process manuallyPrimitive casts have not been processed properly.
- Class redefinition is not built in yet, it needs to tweak MetaClassImpl.