GraalVM Compiler

The GraalVM compiler is a dynamic just-in-time (JIT) compiler, written in Java, that transforms bytecode into machine code. The GraalVM compiler integrates with Java HotSpot VM that supports a compatible version of the JVM Compiler Interface (JVMCI). JVMCI is a privileged low-level interface to the JVM, enabling a compiler written in Java to be used by the JVM as a dynamic compiler (see JEP 243. It can read metadata from the VM, such as method bytecode, and install machine code into the VM
. GraalVM includes a version of the HotSpot JVM that supports JVMCI.

Compiler Advantages #

The GraalVM compiler provides optimized performance for programs running on the JVM through unique approaches to code analysis and optimization. It includes multiple optimization algorithms (called “Phases”) like aggressive inlining, polymorphic inlining, and others. For example, the GraalVM Enterprise compiler includes 62 optimization phases, of which 27 are patented.

The GraalVM compiler assures performance advantages for highly abstracted programs due to its ability to remove costly object allocations. Code using more abstraction and modern Java features like Streams or Lambdas will see greater speedups. Low level code or code that converge to things like I/O, memory allocation, or garbage collection will see less improvement. Consequently, an application running on GraalVM needs to spend less time doing memory management and garbage collection. For more information on performance tuning, refer to Compiler Configuration on JVM.

Graph Compilation #

To run guest programming languages, namely JavaScript, Ruby, R, Python, and WebAssembly in the same runtime as the host JVM-based languages, the compiler should work with a language-independent intermediate representation (IR) between the source language and the machine code to be generated. A graph was selected for this role.

The graph can represent similar statements of different languages, like “if” statements or loops, in the same way, which makes it possible to mix languages in the same program. The GraalVM compiler can perform then language-independent optimization and generate machine code on this grpah.

GraalVM also includes the Language Implementation Framework – a library, written in Java, to build interpreters for programming languages, which then run on GraalVM. These languages can consequently benefit from the optimization possibilities of the GraalVM compiler. The pipeline for such compilation is:

  • The Language Implementation Framework code and data (Abstract Syntax Trees) is partially evaluated to produce a compilation graph. When such an Abstract Syntax Tree (AST) is hot (i.e., called many times), it is scheduled for compilation by the compiler.
  • The compilation graph is optimized by the GraalVM compiler to produce machine code.
  • JVMCI installs this machine code in the VM’s code cache.
  • The AST will automatically redirect execution to the installed machine code once it is available.

Ahead-of-time Compilation #

Besides the Language Implementation Framework, GraalVM incorporates its optimizing compiler into an advanced ahead-of-time (AOT) compiation technology – Native Image, that translates Java and JVM-based code into a native platform executable. These native executables start nearly instantaneously, are smaller, and consume less resources of the same Java application, which makes them ideal for cloud deployments and microservices. For more information about AOT compilation, go to Native Image.

Compiler Operating Modes #

There are two operating modes of the GraalVM compiler when used as a HotSpot JIT compiler: as pre-compiled machine code (“libgraal”), or as dynamically executed Java bytecode (“jargraal”).

libgraal: the GraalVM compiler is compiled ahead-of-time into a native shared library. In this operating mode, the shared library is loaded by the HotSpot VM. The compiler uses memory separate from the HotSpot heap and it runs fast from the start since it does not need to warm-up. This is the default and recommended mode of operation.

jargraal: the GraalVM compiler goes through the same warm-up phase that the rest of Java application does. That is, it is first interpreted before its hot methods are compiled. This mode is selected with the -XX:-UseJVMCINativeLibrary command line option.

Diagnostic Data #

If an uncaught exception is thrown by the compiler, the compilation is simply discarded and execution continues. However, the GraalVM compiler can instead produce diagnostic data (such as compiler immediate representation graphs) that can be submitted along with a bug report. This is enabled with -Dgraal.CompilationFailureAction=Diagnose. The default location of the diagnostics output is in graal_dumps/ under the current working directory of the process but can be changed with the -Dgraal.DumpPath option. During the VM shutdown, the location of the archive containing the diagnostic data is printed to the console.

Furthermore, diagnostic data can be produced for any compilation performed by the GraalVM compiler with the -Dgraal.Dump option. This will produce diagnostic data for every method compiled by the compiler. To refine the set of methods for which diagnostic data is produced, use the -Dgraal.MethodFilter=<class>.<method> option. For example, -Dgraal.MethodFilter=java.lang.String.*,HashMap.get will produce diagnostic data only for methods in the java.lang.String class as well as methods named get in a class whose non-qualified name is HashMap.

Instead of being written to a file, diagnostic data can also be sent over the network to Ideal Graph Visualizer. This requires the -Dgraal.PrintGraph=Network option, upon which the compiler will try to send diagnostic data to 127.0.0.1:4445. This network endpoint can be configured with the -Dgraal.PrintGraphHost and -Dgraal.PrintGraphPort options. Note: Ideal Graph Visualizer is available with Oracle GraalVM Enterprise Editon.