From 2f7f25e9961720f430a5a045ad023372ad36ac55 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Sat, 17 May 2008 17:14:52 +0000 Subject: [PATCH] Set up basic jit compiling framework. --- src/core/org/luaj/vm/LPrototype.java | 3 + src/debug/org/luaj/debug/Print.java | 2 +- src/script/org/luaj/jit/JitPrototype.java | 38 ++ src/script/org/luaj/jit/LuaJit.java | 457 ++++++++++++++++++++++ 4 files changed, 499 insertions(+), 1 deletion(-) create mode 100644 src/script/org/luaj/jit/JitPrototype.java create mode 100644 src/script/org/luaj/jit/LuaJit.java diff --git a/src/core/org/luaj/vm/LPrototype.java b/src/core/org/luaj/vm/LPrototype.java index ec25b5db..3cb3eca9 100644 --- a/src/core/org/luaj/vm/LPrototype.java +++ b/src/core/org/luaj/vm/LPrototype.java @@ -29,6 +29,9 @@ package org.luaj.vm; public class LPrototype { public LPrototype() { } + public LClosure newClosure(LTable env) { + return new LClosure(this,env); + } /* constants used by the function */ public LValue[] k; diff --git a/src/debug/org/luaj/debug/Print.java b/src/debug/org/luaj/debug/Print.java index 9818dbfb..d01780d1 100644 --- a/src/debug/org/luaj/debug/Print.java +++ b/src/debug/org/luaj/debug/Print.java @@ -141,7 +141,7 @@ public class Print extends Lua { } } - static void printOpCode(LPrototype f, int pc) { + public static void printOpCode(LPrototype f, int pc) { int[] code = f.code; int i = code[pc]; int o = GET_OPCODE(i); diff --git a/src/script/org/luaj/jit/JitPrototype.java b/src/script/org/luaj/jit/JitPrototype.java new file mode 100644 index 00000000..d2407be2 --- /dev/null +++ b/src/script/org/luaj/jit/JitPrototype.java @@ -0,0 +1,38 @@ +package org.luaj.jit; + +import org.luaj.vm.LClosure; +import org.luaj.vm.LPrototype; +import org.luaj.vm.LTable; +import org.luaj.vm.LuaState; + +abstract +public class JitPrototype extends LPrototype { + + protected LPrototype p; + + public JitPrototype() { + super(); + } + + protected void setLuaPrototype(LPrototype lp) { + this.p = lp; + } + + public LClosure newClosure(LTable env) { + return new JitClosure(this, env); + } + + private static final class JitClosure extends LClosure { + private final JitPrototype jp; + public JitClosure(JitPrototype jitPrototype, LTable env) { + super( jitPrototype.p, env ); + this.jp = jitPrototype; + } + public boolean luaStackCall(LuaState vm) { + jp.jitCall(vm,env); + return false; + } + } + + public abstract void jitCall( LuaState vm, LTable env ); +} diff --git a/src/script/org/luaj/jit/LuaJit.java b/src/script/org/luaj/jit/LuaJit.java new file mode 100644 index 00000000..116289c6 --- /dev/null +++ b/src/script/org/luaj/jit/LuaJit.java @@ -0,0 +1,457 @@ +package org.luaj.jit; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; + +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; + +import org.luaj.compiler.LuaC; +import org.luaj.debug.Print; +import org.luaj.platform.J2sePlatform; +import org.luaj.vm.LClosure; +import org.luaj.vm.LPrototype; +import org.luaj.vm.LTable; +import org.luaj.vm.LValue; +import org.luaj.vm.Lua; +import org.luaj.vm.LuaState; +import org.luaj.vm.Platform; + +public class LuaJit extends Lua { + + public static void main(String[] args) throws IOException { + + Platform.setInstance(new J2sePlatform()); + LuaC.install(); + + String program = "print 'starting'\nfor i=1,10 do\n\tprint 'hello, world'\nend"; + InputStream is = new ByteArrayInputStream(program.getBytes()); + LPrototype p = LuaC.compile(is, "program"); + test( p ); + LPrototype q = LuaJit.compile( p ); + test( q ); +// JitPrototype jp = new JitPrototypeOne(); +// jp.setLuaPrototype(p); +// test( jp ); + } + + private static void test(LPrototype p) { + try { + LuaState vm = Platform.newLuaState(); + LClosure c = p.newClosure(vm._G); + vm.pushlvalue(c); + vm.call(0, 0); + } catch ( Throwable e ) { + e.printStackTrace(); + } + } + + public static LPrototype compile( LPrototype p ) { + int i, a, b, c, o, n, cb; + LValue rkb, rkc, nvarargs, key, val; + LValue i0, step, idx, limit, init, table; + boolean back, body; + + PrintWriter pw = new PrintWriter( System.out ); + String name = "JitPrototypeOne"; + pw.print( + "package org.luaj.jit;\n"+ + "import org.luaj.vm.LTable;\n"+ + "import org.luaj.vm.LuaState;\n"+ + "public class "+name+" extends JitPrototype {\n"+ + " public void jitCall(LuaState vm, LTable env) {\n"+ + "" ); + + int[] code = p.code; + LValue[] k = p.k; + + // loop until a return instruction is processed, + // or the vm yields + for ( int pc=0; pc> POS_OP) & MAX_OP; + a = (i >> POS_A) & MAXARG_A; + + switch (o) { + case LuaState.OP_MOVE: { + b = LuaState.GETARG_B(i); + // this.stack[base + a] = this.stack[base + b]; + pw.println( "\t\tvm.stack[base+"+a+"] = vm.stack[base+"+b+"];" ); + continue; + } + case LuaState.OP_LOADK: { + b = LuaState.GETARG_Bx(i); + // this.stack[base + a] = k[b]; + pw.println( "\t\tvm.stack[base+"+a+"] = p.k["+b+"];" ); + continue; + } + /* + case LuaState.OP_LOADBOOL: { + b = LuaState.GETARG_B(i); + c = LuaState.GETARG_C(i); + this.stack[base + a] = (b != 0 ? LBoolean.TRUE : LBoolean.FALSE); + if (c != 0) + ci.pc++; // skip next instruction (if C) + continue; + } + case LuaState.OP_LOADNIL: { + b = LuaState.GETARG_B(i); + do { + this.stack[base + b] = LNil.NIL; + } while ((--b) >= a); + continue; + } + case LuaState.OP_GETUPVAL: { + b = LuaState.GETARG_B(i); + this.stack[base + a] = cl.upVals[b].getValue(); + continue; + } + */ + case LuaState.OP_GETGLOBAL: { + b = LuaState.GETARG_Bx(i); + // key = k[b]; + // table = cl.env; + // top = base + a; + // table.luaGetTable(this, table, key); + // pw.println("\t\tvm.top = base+"+a+";"); + pw.println("\t\tvm.settop("+a+");"); + pw.println("\t\tenv.luaGetTable(vm, env, p.k["+b+"]);"); + continue; + } + /* + case LuaState.OP_GETTABLE: { + b = LuaState.GETARG_B(i); + key = GETARG_RKC(k, i); + table = this.stack[base + b]; + top = base + a; + table.luaGetTable(this, table, key); + continue; + } + case LuaState.OP_SETGLOBAL: { + b = LuaState.GETARG_Bx(i); + key = k[b]; + val = this.stack[base + a]; + table = cl.env; + table.luaSetTable(this, table, key, val); + continue; + } + case LuaState.OP_SETUPVAL: { + b = LuaState.GETARG_B(i); + cl.upVals[b].setValue( this.stack[base + a] ); + continue; + } + case LuaState.OP_SETTABLE: { + key = GETARG_RKB(k, i); + val = GETARG_RKC(k, i); + table = this.stack[base + a]; + table.luaSetTable(this, table, key, val); + continue; + } + case LuaState.OP_NEWTABLE: { + b = LuaState.GETARG_B(i); + c = LuaState.GETARG_C(i); + this.stack[base + a] = new LTable(b, c); + continue; + } + case LuaState.OP_SELF: { + rkb = GETARG_RKB(k, i); + rkc = GETARG_RKC(k, i); + top = base + a; + rkb.luaGetTable(this, rkb, rkc); + this.stack[base + a + 1] = rkb; + // StkId rb = RB(i); + // setobjs2s(L, ra+1, rb); + // Protect(luaV_gettable(L, rb, RKC(i), ra)); + continue; + } + case LuaState.OP_ADD: + case LuaState.OP_SUB: + case LuaState.OP_MUL: + case LuaState.OP_DIV: + case LuaState.OP_MOD: + case LuaState.OP_POW: { + rkb = GETARG_RKB(k, i); + rkc = GETARG_RKC(k, i); + this.stack[base + a] = rkc.luaBinOpUnknown(o, rkb); + continue; + } + case LuaState.OP_UNM: { + rkb = GETARG_RKB(k, i); + this.stack[base + a] = rkb.luaUnaryMinus(); + continue; + } + case LuaState.OP_NOT: { + rkb = GETARG_RKB(k, i); + this.stack[base + a] = (!rkb.toJavaBoolean() ? LBoolean.TRUE + : LBoolean.FALSE); + continue; + } + case LuaState.OP_LEN: { + rkb = GETARG_RKB(k, i); + this.stack[base + a] = LInteger.valueOf( rkb.luaLength() ); + continue; + } + case LuaState.OP_CONCAT: { + b = LuaState.GETARG_B(i); + c = LuaState.GETARG_C(i); + int numValues = c - b + 1; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int j = b, l = 0; j <= c; j++, l++) { + this.stack[base + j].luaConcatTo( baos ); + } + this.stack[base + a] = new LString( baos.toByteArray() ); + continue; + } + case LuaState.OP_JMP: { + ci.pc += LuaState.GETARG_sBx(i); + continue; + } + case LuaState.OP_EQ: + case LuaState.OP_LT: + case LuaState.OP_LE: { + rkb = GETARG_RKB(k, i); + rkc = GETARG_RKC(k, i); + boolean test = rkc.luaBinCmpUnknown(o, rkb); + if (test == (a == 0)) + ci.pc++; + continue; + } + case LuaState.OP_TEST: { + c = LuaState.GETARG_C(i); + if (this.stack[base + a].toJavaBoolean() != (c != 0)) + ci.pc++; + continue; + } + case LuaState.OP_TESTSET: { + rkb = GETARG_RKB(k, i); + c = LuaState.GETARG_C(i); + if (rkb.toJavaBoolean() != (c != 0)) + ci.pc++; + else + this.stack[base + a] = rkb; + continue; + } + case LuaState.OP_CALL: { + + // ra is base of new call frame + this.base += a; + + // number of args + b = LuaState.GETARG_B(i); + if (b != 0) // else use previous instruction set top + top = base + b; + + // number of return values we need + c = LuaState.GETARG_C(i); + + // make or set up the call + this.nresults = c - 1; + if (this.stack[base].luaStackCall(this)) + return; + + // adjustTop only for case when call was completed + // and number of args > 0. If call completed but + // c == 0, leave top to point to end of results + if (c > 0) + adjustTop(base + c - 1); + + // restore base + base = ci.base; + + continue; + } + + case LuaState.OP_TAILCALL: { + closeUpVals(base); + + // copy down the frame before calling! + + // number of args (including the function) + b = LuaState.GETARG_B(i); + if (b == 0) + b = top - (base + a); + + // copy call + all args, discard current frame + System.arraycopy(stack, base + a, stack, ci.resultbase, b); + this.base = ci.resultbase; + this.top = base + b; + this.nresults = ci.nresults; + --cc; + + // make or set up the call + try { + if (this.stack[base].luaStackCall(this)) { + return; + } + } catch (LuaErrorException e) { + // in case of lua error, we need to restore cc so that + // the debug can get the correct location where the error + // occured. + cc++; + throw e; + } + + // adjustTop only for case when call was completed + // and number of args > 0. If call completed but + // c == 0, leave top to point to end of results + if (this.nresults >= 0) + adjustTop(base + nresults); + + // force restore of base, etc. + return; + } + + case LuaState.OP_RETURN: { + // number of return vals to return + b = LuaState.GETARG_B(i) - 1; + if (b == -1) + b = top - (base + a); + + // close open upvals + closeUpVals( base ); + + // number to copy down + System.arraycopy(stack, base + a, stack, ci.resultbase, b); + top = ci.resultbase + b; + + // adjust results to what caller expected + if (ci.nresults >= 0) + adjustTop(ci.resultbase + ci.nresults); + + // pop the call stack + --cc; + + // force a reload of the calling context + return; + } + case LuaState.OP_FORLOOP: { + i0 = this.stack[base + a]; + step = this.stack[base + a + 2]; + idx = step.luaBinOpUnknown(Lua.OP_ADD, i0); + limit = this.stack[base + a + 1]; + back = step.luaBinCmpInteger(Lua.OP_LT, 0); + body = (back ? idx.luaBinCmpUnknown(Lua.OP_LE, limit) : limit + .luaBinCmpUnknown(Lua.OP_LE, idx)); + if (body) { + this.stack[base + a] = idx; + this.stack[base + a + 3] = idx; + top = base + a + 3 + 1; + ci.pc += LuaState.GETARG_sBx(i); + } + continue; + } + case LuaState.OP_FORPREP: { + init = this.stack[base + a]; + step = this.stack[base + a + 2]; + this.stack[base + a] = step.luaBinOpUnknown(Lua.OP_SUB, init); + b = LuaState.GETARG_sBx(i); + ci.pc += b; + continue; + } + case LuaState.OP_TFORLOOP: { + cb = base + a + 3; // call base + base = cb; + adjustTop( cb + 3 ); + System.arraycopy(this.stack, cb-3, this.stack, cb, 3); + + // call the iterator + c = LuaState.GETARG_C(i); + this.nresults = c; + if (this.stack[cb].luaStackCall(this)) + execute(); + base = ci.base; + adjustTop( cb + c ); + + // test for continuation + if (!this.stack[cb].isNil() ) { // continue? + this.stack[cb-1] = this.stack[cb]; // save control variable + } else { + ci.pc++; // skip over jump + } + continue; + } + case LuaState.OP_SETLIST: { + b = LuaState.GETARG_B(i); + c = LuaState.GETARG_C(i); + int listBase = base + a; + if (b == 0) { + b = top - listBase - 1; + } + if (c == 0) { + c = code[ci.pc++]; + } + int offset = (c-1) * LFIELDS_PER_FLUSH; + LTable tbl = (LTable) this.stack[base + a]; + for (int j=1; j<=b; j++) { + tbl.put(offset+j, stack[listBase + j]); + } + top = base + a - 1; + continue; + } + case LuaState.OP_CLOSE: { + closeUpVals( base + a ); // close upvals higher in the stack than position a + continue; + } + case LuaState.OP_CLOSURE: { + b = LuaState.GETARG_Bx(i); + proto = cl.p.p[b]; + newClosure = new LClosure(proto, cl.env); + for (int j = 0; j < newClosure.upVals.length; j++, ci.pc++) { + i = code[ci.pc]; + o = LuaState.GET_OPCODE(i); + b = LuaState.GETARG_B(i); + if (o == LuaState.OP_GETUPVAL) { + newClosure.upVals[j] = cl.upVals[b]; + } else if (o == LuaState.OP_MOVE) { + newClosure.upVals[j] = findUpVal( base + b ); + } else { + throw new java.lang.IllegalArgumentException( + "bad opcode: " + o); + } + } + this.stack[base + a] = newClosure; + continue; + } + case LuaState.OP_VARARG: { + // figure out how many args to copy + b = LuaState.GETARG_B(i) - 1; + nvarargs = this.stack[base - 1]; + n = nvarargs.toJavaInt(); + if (b == LuaState.LUA_MULTRET) { + b = n; // use entire varargs supplied + } + + // copy args up to call stack area + checkstack(a+b); + for (int j = 0; j < b; j++) + this.stack[base + a + j] = (j < n ? this.stack[base + - n + j - 1] + : LNil.NIL); + top = base + a + b; + continue; + } + */ + } + } + pw.print( "\n"+ + " return false;\n"+ + " }\n"+ + "}\n" ); + pw.flush(); + return p; + + } + +}