Compiling Scheme to JVM bytecode

Tony Garnock-Jones <[email protected]> Mon, 14 Jun 2004 17:45:44 +0100
Newsgroups gmane.comp.java.sisc.devel
Message-ID <[email protected]>
Hi all.

I've been working on a simple Scheme compiler for a while now. Until
recently I was targeting .NET, but I'm now switching over to the
JVM. I've been thinking about how I might integrate the compiled code
with SISC, to take advantage of the more-or-less complete runtime and
make use of parts of the design (such as serialisation).

The compiler supports proper tail-calls, and uses CPS as its internal
representation for continuations-as-cheap-as-closures. The few simple
benchmarks I've done show the following setup performing reasonably
well, given the constraints (I've removed some irrelevant detail):

     public abstract class Closure {
	public abstract void apply_compiled(Object[] args,
                                             Trampoline next);
     }

     public class Trampoline {
	public Closure closure;
	public Object[] args;

	public Object call(Closure closure, Object[] args) {
	    this.closure = closure;
	    this.args = new Object[args.length + 2];

	    this.args[0] = new ToplevelContinuation();
	    System.arraycopy(args, 0, this.args, 1, args.length);

	    while (this.closure != null) {
		this.closure.apply_compiled(this.args, this);
	    }

	    return this.args[0];
	}

	public class ToplevelContinuation extends Closure {
	    public void apply_compiled(Object[] args, Trampoline next) {
		next.args = new Object[] { args[0] };
		next.closure = null;
	    }
	}
     }

This is close to being, but not quite the same as, the calling
convention used in SISC at the moment. The simplest means of
integrating the two evaluation styles could be:

     - extend class Value with
       public void apply_compiled(Value[] args, Interpreter r)
       which expects a continuation as args[0].

     - implement some class CompiledProcedure extends Procedure, with
       an apply(Interpreter) method similar to Trampoline.call above,
       setting things up for a call to apply_compiled, except instead
       of putting in a new ToplevelContinuation, the current
       continuation from the Interpreter would be capture()d and passed
       along.

     - class Procedure would override apply_compiled, doing the
       inverse: setting up r.nxp and r.vlr etc etc. for a call to
       apply(), and pushing the continuation in args[0] onto the
       interpreter's context.

This way, calls back and forth between compiled and interpreted
procedures is reasonably transparent, and continuation capture Just
Works for both halves.

I'd appreciate feedback on this general outline. Am I missing anything
important? Is there any way this design could be improved upon?

Regards,
   Tony



-------------------------------------------------------
This SF.Net email is sponsored by The 2004 JavaOne(SM) Conference
Learn from the experts at JavaOne(SM), Sun's Worldwide Java Developer
Conference, June 28 - July 1 at the Moscone Center in San Francisco, CA
REGISTER AND SAVE! http://java.sun.com/javaone/sf Priority Code NWMGYKND