A meta-circular Java bytecode interpreter for the GraalVM.
Espresso is a fully meta-circular implementation of The Java Virtual Machine Specification, Java SE 8 and 11 Edition, written in Java, capable of running non-trivial programs at speed.
A Java bytecode interpreter at its core, turned Just-In-Time (JIT) compiler by leveraging Truffle and the Graal compiler on the GraalVM.
It highlights the sublime potential of the GraalVM as a platform for implementing high-performance languages and runtimes.
Espresso is still an early prototype, but it already passes the Java Compatibility Kit (a.k.a. the JCK or TCK for Java SE) 8c and 11 runtime suite.
Espresso can compile itself with both javac
and (the Eclipse Java Compiler) ecj
.
It features complete meta-circularity: it can run itself any amount of layers deep, preserving all the capabilities (Unsafe, JNI, Reflection...) of the base layer. Running HelloWorld on three nested layers of Espresso takes ~15 minutes.
Espresso is similar to HotSpot Express, the same codebase can run either an 8 or 11 guest JVM, on either an 8 or 11 host JVM.
The development of Espresso happens mostly on HotSpot, but this configuration (Espresso on HotSpot) is only supported on Linux, see Limitations
.
Espresso's native image runs on Linux, MacOS and Windows.
Set your (JVMCI-enabled) JDK via mx
argument e.g. mx --java-home /path/to/java/home ...
or via export JAVA_HOME=/path/to/java/home
.
mx build
-ing Espresso creates a GraalVM with Espresso included.
To build the default configuration (interpreter-only), on the espresso
repository:
$ mx build
Other configurations are provided:
$ mx --env jvm build # GraalVM CE + Espresso jars (interpreter only)
$ mx --env jvm-ce build # GraalVM CE + Espresso jars (JIT)
$ mx --env native-ce build # GraalVM CE + Espresso native (JIT)
# Use the same --env argument used to build.
$ export ESPRESSO=`mx --env native-ce graalvm-home`/bin/espresso
Configuration files: mx.espresso/{jvm,jvm-ce,native-ce}
and mx.espresso/native-image.properties
mx espresso
runs Espresso (from jars or native) from within a GraalVM. It mimics the java
(8|11) command. Bare mx espresso
runs Espresso on interpreter-only mode.
$ mx --env jvm-ce build # Always build first
$ mx --env jvm-ce espresso -cp my.jar HelloWorld
To build and run Espresso native image:
$ mx --env native-ce build # Always build first
$ mx --env native-ce espresso -cp my.jar HelloWorld
The mx espresso
launcher adds some overhead, to execute Espresso native image directly use:
$ mx --env native-ce build # Always build first
$ export ESPRESSO=`mx --env native-ce graalvm-home`/bin/espresso
$ time $ESPRESSO -cp my.jar HelloWorld
To run Espresso on a vanilla JDK (8|11) and/or not within a GraalVM use mx espresso-standalone ...
, it mimics the java
(8|11) command. The launcher adds all jars and properties required to run Espresso on any vanilla JDK (8|11).
To debug Espresso:
$ mx build
$ mx -d espresso-standalone -cp mxbuild/dists/jdk1.8/espresso-playground.jar com.oracle.truffle.espresso.playground.HelloWorld
It can also run on a GraalVM with JIT compilation:
$ mx build
$ mx --dy /compiler espresso-standalone -cp my.jar HelloWorld
$ mx -v --dy /compiler -J"-Dgraal.Dump=:4 -Dgraal.TraceTruffleCompilation=true -Dgraal.TruffleBackgroundCompilation=false" espresso-standalone -cp mxbuild/dists/jdk1.8/espresso-playground.jar com.oracle.truffle.espresso.playground.TestMain
By default, Espresso runs within a GraalVM and it reuses the jars and native libraries shipped with GraalVM. But it's possible to specify a different Java home, even with a different version; Espresso will automatically switch versions regardless of the host JVM.
$ mx build
$ mx espresso -version
$ mx espresso --java.JavaHome=/path/to/java/8/home -version
$ mx espresso --java.JavaHome=/path/to/java/11/home -version
Espresso relies on glibc's dlmopen to run on HotSpot, but this approach has limitations that lead to crashes e.g. libnio.so: undefined symbol: fstatat64
. Some of these limitations can be by avoided by defining LD_DEBUG=unused
e.g.
$ LD_DEBUG=unused mx espresso -cp mxbuild/dists/jdk1.8/espresso-playground.jar com.oracle.truffle.espresso.playground.Tetris
Self-hosting requires a Linux distribution with an up-to-date glibc.
Use mx espresso-meta
to run programs on Espresso². Ensure to prepend LD_DEBUG=unused
to overcome a known glibc bug.
To run HelloWorld on Espresso² execute the following:
$ mx build
$ LD_DEBUG=unused mx --dy /compiler espresso-meta -cp my.jar HelloWorld
It takes some time for both (nested) VMs to boot, only the base layer is blessed with JIT compilation. Enjoy!