Hello and welcome to the first part of our series on implementing a JVM in Rust!
Firstly, I’ve decided make some changes to this project. I’ve moved the target from a compliant JVM8 spec to the JVM11 spec. This is because compiling the OpenJDK8 has been a pain in the ass. Nothing much should change for the JVM implementation. The biggest change should be class lookup since now we have to deal with modules.
On this post I’ll actually just go through how to get the sources for OpenJDK11, compile it and import it into an IDE.
I didn’t have too much time these weeks for a more detailed post, so this will be a short one. On our next post we will actually start implementing some stuff!
OpenJDK currently uses Mercurial SCM for Version Control Management. Chances are you do not know or have Mercurial installed, but luckily there are mirrors for many OpenJDK versions up on Github!
Right now we are interested in the OpenJDK11 (GitHub) repository. So go ahead and clone it!
Setting Up The Environment
The first thing you will need is a JDK11 set up on your system to bootstrap the compilation of the JDK. You can check out how to get it and install it here: https://adoptopenjdk.net/
I’ll be using the HotSpot JVM since it’s the one I’m most used to. Just don’t forget to select the OpenJDK11 version.
Secondly, you need to run the
configure script for the repository. Inside the cloned repository run:
$ chmod +x ./configure $ JAVA_HOME=/opt/jdk11 ./configure — with-debug-level=slowdebug — disable-warnings-as-errors
First we need to enable the execution flag in the
configure script. Secondly we need to run the configure script. I’m setting the flag to enable debug information to help us in the future. We also disable the option
C++ compiler so we can actually compile the HotSpot code.
Notice I setup the
JAVA_HOME environment variable for the execution. This is because I usually have other JDKs installed on my computer, this is just so I can set the correct one. If you do not have other JDKs you can omit that part of the command.
During the execution of the script it will verify if you have all the necessary tools and libraries for compiling the project. If anything is missing the script will show you helpful information on how to install the missing dependencies. Just keep running the command and installing the dependencies until the script executes successfully.
Finally, the OpenJDK project is Makefile based. CLion is not a big fan of raw Makefile projects. To enable code navigation we need to create a
compile_commands.json file for the project. This files enables CLion to know where to look for source code, headers, etc. This is specially important considering the OpenJDK is a mixed language project, including
To help us with that we will use the
compiledb command. It is installed through
pip. First install
pip if you haven’t already:
$ sudo apt install python-pip
$ pip install compiledb
Finally we can compile the OpenJDK code. Because we are only interested in the HotSpot code for this project (the actual JMV) we need to run
$ compiledb make hotspot
This might take some time. After finishing the command you should have a
compile_commands.json file at the root of your repository.
Importing Into CLion
This is the easiest step!
Just go into CLion, import a new project from existing sources and select the folder where you cloned your project into. Everything should be automatic from there.
Navigating The Project
After importing the project into CLion you can check the source code. Our main interest is in the folder
src/hotspot. This is where the (mostly)
C++ code for the JVM system resides. You can notice that it is split into 4 main folders,
Our main interest is in the
os introduces primitives per supported
os. The folder
os_cpu merges both folders so we have primitives for each
os pair. When you run the
configure script it figures out which OS and CPU you are currently using and set up things in a way that only source code that is relevant to you will be compiled (unless you say otherwise, of course).
share folder contains all the goodies we want to learn. There you can find the classfile parser, runtime information. bytecode interpreter, source code for the garbage collects and way more! Take your time to get familiar with it and check if the source code navigation is working as expected.
If you want to start working out the inner workings of the JVM, go to the file
src/hotspot/share/prims/jni.cpp. There you can find the function
JNI_CreateJavaVM. This is the entry point for the JVM, where it’s created, it’s main thread initialized and parameters processed. For now you don’t need to worry about who calls it.
If you want to read more about how the HotSpot JVM is set up I’ll leave you with a couple of links with some reading material:
Now that we are able to read an navigate what is probably the main implementation of a JVM we can start doing some work!
But first we need to understand what we are actually implementing. The description of how the JVM works is found in it’s spec (The Java® Virtual Machine Specification). Get familiar with the structure of this document so we can navigate it quickly once we start to code.
See you soon!