Friday, February 04, 2022

Jacobin JVM project after six months

After six months, Jacobin can now execute many of the most common bytecode instructions. Simple classes that use for-loops, call methods that compute values, and print the results to the screen work correctly. Several of these are now available in the testdata directory on GitHub. For example, Hello3.class performs the following:

public static void main( String[] args) {
int x;
for( int i = 0; i < 10; i++) {
    x = addTwo(i, i-1);
    System.out.println( x );

  static int addTwo(int j, int k) {
int m = multTwo(j, k);
return m+1;

  static int multTwo(int m, int n){
return m*n;

What you're seeing is a loop that calls a method, which in turn calls another method. If you run this without any command-line options, it will print out the expected result (a series of integers ranging from 1 to 73). 

If you run it with -verbose:finest, Jacobin will present a wealth of information about what's going on inside the JVM. You can also do instruction-level tracing with -trace:inst. The last few lines of the instruction trace look like this:

class: Hello3, meth: main, pc: 20, inst: INVOKEVIRTUAL, tos: 1
class: Hello3, meth: main, pc: 23, inst: IINC, tos: -1
class: Hello3, meth: main, pc: 26, inst: GOTO, tos: -1
class: Hello3, meth: main, pc: 2, inst: ILOAD_2, tos: -1
class: Hello3, meth: main, pc: 3, inst: BIPUSH, tos: 0
class: Hello3, meth: main, pc: 5, inst: IF_ICMPGE, tos: 1
class: Hello3, meth: main, pc: 29, inst: RETURN, tos: -1

The class and method fields are self-explanatory. pc refers to the location of the bytecode instruction, inst: refers to the actual instruction, and tos: represents the top of the operand stack before the instruction (-1 = empty stack, 0 = 1 item on the stack, etc.)

When you run Jacobin, it loads some 1500 Java classes in the background (just like the JVM does). If you want to see the list of these classes, run Jacobin with the -verbose:class command-line option. (A tribute to both the go language implementation and the design of Java classes is that these 1500 classes can be read, parsed, and posted in less than 300ms.) 

Current work

We're presently working on object creation. (So far, all the test classes don't require the creation of new objects.) The next step will then be handling exceptions, and then running classes that are in separate source files. As we create test classes for these developments, we'll perforce be adding new bytecode instructions to our interpreter. 

By the numbers

As of February 1 (six months into the project) the project spans 52 files consisting of 17,588 lines. Our pipeline consists of 223 tests and 11,922 lines (code and data) making our testing corpus 2.10x the size of our production code. We'll be looking to increase this ratio going forward. (It was 1.4x at the three-month mark.)

How you can help

If you're interested in this project and you're on Github, we'd love a star. Knowing people are interested in Jacobin really helps keep our motivation and spirits high. If you're on Twitter, follow our handle (@jacobin_jvm). Thanks for your interest and support!