Building a Java Virtual Machine: How hard could it be?

Ben Zotto
11 min readJan 2, 2021

Part 1 of a series discussing the joys and pitfalls (mostly pitfalls) of hacking together a minimal JVM in Javascript. The live code base — a very rough work in progress! — is on GitHub. Subscribe for further updates! ;-)

This past summer, I had a conversation with a friend about his need to run small Java programs in a web page. It was a pandemic summer and I had some time, so this made me wonder how hard it would be to put together a small, simple Java Virtual Machine (JVM) in Javascript. I have done some hobby work on CPU emulation, but… I haven’t actually worked in Java or Javascript since about 2010. So ha ha ha, I was completely unqualified.

My goal was to get Hello World to run, which is to say, this bit of code:

class HelloWorld extends Object {
public static void main(String[] args) {
System.out.println("Hello World");

If you compile and run this file in a terminal, you get this:

% javac 
% java HelloWorld
Hello World

The first step invokes the compiler (javac) which produces a file called HelloWorld.class. The second step executes the compiled class’s main method.

I was interested in the second half, executing the compiled class file. I wasn’t sure how the output part was going to work but figured I’d plow in and see how far I got.

So I opened up a scratch HTML page and a scratch JS file and figured I’d try to load this class file.

Buster says Java is where it’s at

What are we working with here?

Might as well start with a look at this HelloWorld.class file. It’s 425 bytes long and it looks like this:

CAFEBABE 0000003B 001D0A00 02000307 00040C00 05000601 00106A61 76612F6C 616E672F 4F626A65 63740100 063C696E 69743E01 00032829 56090008 00090700 0A0C000B 000C0100 106A6176 612F6C61 6E672F53 79737465 6D010003 6F757401 00154C6A 6176612F 696F2F50 72696E74 53747265 616D3B08 000E0100 0B48656C 6C6F2057 6F726C64 0A001000 11070012 0C001300 14010013 6A617661 2F696F2F 5072696E 74537472…