Wow - it's been two weeks!
Indeed... But what have I been up to?
Well, if you'd kept up with CVS, you'd know that a week ago I was dealing with symbolic name resolution as per the JVM Spec.
I was kinda delayed by a bug in javac's compile-time field resolution. I kept testing my algorithm against javac's, and so I had to redo it to match the JVM's dynamic resolution method - which is the correct one, according to the specification. I filed a bug with Sun (no response yet) - but it's a corner case (not that important). I just wanted to get it right the first time.
That's not the main reason for this post, though. I've just committed a version of the code that finally does something - like visible stuff.
The interpreter now “loads” the necessary classes (that was the step following resolution), parsing the bytecode and building a structure suitable for the interpretation process.
I was going to go with an int[]
and the traditional switch
interpreter, but after implementing just “a couple” of opcodes I was rapidly approaching the maximum method size limit (besides having a huge source file, but that's manageable with code folding).
So I gave up, and I'm using an Insn[]
- that's an “instructions” array. Insn
s are objects that represent an instruction and all its arguments, and which have an execute(...)
virtual method.
The interpreter cycle is now just this (code which I believe explains itself):
while (this.frame != null) this.code[this.cp++].execute(this);
I've implemented a couple of opcodes already, quite enough for dear “Hello World!” - which was in fact the initial goal:
- static and virtual, interpreted and native invocations;
- static and instance field getting and setting;
- local variable loading and storing
- constant loading;
- simple stack operations.
It's not much (no math yet, amongst other things) but as I said enough to test.
Want to give it a try? Easy steps then:
Notes: leave the password blank; you'll need a recent version ofcvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/jauvm login
cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/jauvm co -P jauvm
cd jauvm
ant dist
ant
(mine is 1.6.2) and a 1.5 JDK (mine is 1.5.0_02); and, there will be some warnings about missing serialVersionUID
s.Hopefully, and if all goes out as expected, you'll have 3 files in the dist folder:
- jauvm.jar (java archive, no dependencies);
- jauvm-all.jar (java archive, all dependencies included);
- and, jauvm-src.tgz (source tarball).
You'll want the jauvm-all.jar. Add that to your classpath, compile and run the following example:
Test.java
import net.sf.jauvm.Interpreter;
import net.sf.jauvm.interpretable;
public class Test implements Runnable {
public static void main(String[] args) {
new Interpreter(new Test()).run();
}
public @interpretable void run() {
System.out.println("Hello World!");
System.out.println(System.currentTimeMillis());
iprint(Math.PI);
nprint(Math.E);
itest();
ntest();
}
public @interpretable void itest() {
System.out.println(this);
}
public void ntest() {
itest();
}
public static @interpretable void iprint(double d) {
System.out.println(d);
}
public static void nprint(double d) {
iprint(d);
}
}
The output should be something like:
Hello World!
1123726157960
3.141592653589793
2.718281828459045
Test@e0b6f5
Test@e0b6f5
I'll leave it up to you to figure out what's being interpreted and what's not.
Next steps will be: getting interface and special invocations working (including constructors and
private
methods - super
invocations may be a problem). In the process I hope to implement tail-calls (which seem pretty easy) and a bunch more opcodes, and soften a few rough edges. That's all before getting into continuations.This will now get exiting, at least for me!
No comments:
Post a Comment