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-errorsfrom 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.

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 cpuand 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:

HotSpot Group

HotSpot Runtime Overview

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!