Rust JVM Post 0.5
Introduction
Hello and welcome to the first part of our series on implementing a JVM in Rust!
Well… Kindof…
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!
Getting Sources
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 warning-as-errors
from the 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 C++
, ASM
, C
and Java
sources.
To help us with that we will use the compiledb
command. It is installed through python
’s pip
. First install pip
if you haven’t already:
$ sudo apt install python-pip
Next, install compiledb
$ 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, cpu
, os
, os_cpu
and share
.
Our main interest is in the share
folder. cpu
and os
introduces primitives per supported cpu
and os
. The folder os_cpu
merges both folders so we have primitives for each cpu
and 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).
The 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.
Entry Point
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.
Reading Material
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:
Conclusion
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!