diff --git a/src/core/org/luaj/vm/LClosure.java b/src/core/org/luaj/vm/LClosure.java index 769b4362..2415a0fa 100644 --- a/src/core/org/luaj/vm/LClosure.java +++ b/src/core/org/luaj/vm/LClosure.java @@ -29,23 +29,12 @@ public class LClosure extends LFunction { public LTable env; - /** - * @deprecated construct with environment instead - * @param state - * @param p - */ - public LClosure(LuaState state, LPrototype p) { - this.env = state._G; - this.p = p; - upVals = new UpVal[p.nups]; - } - /** * Construct using a prototype and initial environment. * @param p * @param env */ - public LClosure(LPrototype p, LTable env) { + protected LClosure(LPrototype p, LTable env) { this.p = p; this.env = env; upVals = new UpVal[p.nups]; diff --git a/src/core/org/luaj/vm/LuaState.java b/src/core/org/luaj/vm/LuaState.java index b9613556..01807489 100644 --- a/src/core/org/luaj/vm/LuaState.java +++ b/src/core/org/luaj/vm/LuaState.java @@ -450,7 +450,7 @@ public class LuaState extends Lua { public int load( InputStream is, String chunkname ) { try { LPrototype p = LoadState.undump(this, is, chunkname ); - pushlvalue( new LClosure( p, _G ) ); + pushlvalue( p.newClosure( _G ) ); return 0; } catch ( Throwable t ) { pushstring( t.getMessage() ); @@ -840,7 +840,7 @@ public class LuaState extends Lua { case LuaState.OP_CLOSURE: { b = LuaState.GETARG_Bx(i); proto = cl.p.p[b]; - newClosure = new LClosure(proto, cl.env); + newClosure = proto.newClosure(cl.env); for (int j = 0; j < newClosure.upVals.length; j++, ci.pc++) { i = code[ci.pc]; o = LuaState.GET_OPCODE(i); diff --git a/src/j2se/org/luaj/debug/j2se/StandardLuaJVM.java b/src/j2se/org/luaj/debug/j2se/StandardLuaJVM.java index 28de5c9a..5fb108c8 100644 --- a/src/j2se/org/luaj/debug/j2se/StandardLuaJVM.java +++ b/src/j2se/org/luaj/debug/j2se/StandardLuaJVM.java @@ -193,7 +193,7 @@ public class StandardLuaJVM { LPrototype p = LoadState.undump(state, is, getScript()); // create closure and execute - final LClosure c = new LClosure(p, state._G); + final LClosure c = p.newClosure(state._G); String[] args = getScriptArgs(); int numOfScriptArgs = (args != null ? args.length : 0); LValue[] vargs = new LValue[numOfScriptArgs]; diff --git a/src/sample/org/luaj/sample/LuaRunner.java b/src/sample/org/luaj/sample/LuaRunner.java index 61d1fec3..369d9940 100644 --- a/src/sample/org/luaj/sample/LuaRunner.java +++ b/src/sample/org/luaj/sample/LuaRunner.java @@ -69,7 +69,7 @@ public class LuaRunner { LPrototype p = LoadState.undump(state, is, script); // create closure and execute - LClosure c = new LClosure( p, state._G ); + LClosure c = p.newClosure( state._G ); // do the call state.doCall( c, new LValue[0] ); diff --git a/src/sample/org/luaj/sample/LuajavaRunner.java b/src/sample/org/luaj/sample/LuajavaRunner.java index 48c401ca..ea16975f 100644 --- a/src/sample/org/luaj/sample/LuajavaRunner.java +++ b/src/sample/org/luaj/sample/LuajavaRunner.java @@ -58,7 +58,7 @@ public class LuajavaRunner { LPrototype p = LoadState.undump(state, is, script); // create closure and execute - LClosure c = new LClosure( p, state._G ); + LClosure c = p.newClosure( state._G ); state.doCall(c, new LValue[0]); } diff --git a/src/script/org/luaj/jit/JitPrototype.java b/src/script/org/luaj/jit/JitPrototype.java index d2407be2..57f4c82d 100644 --- a/src/script/org/luaj/jit/JitPrototype.java +++ b/src/script/org/luaj/jit/JitPrototype.java @@ -14,6 +14,10 @@ public class JitPrototype extends LPrototype { super(); } + protected void unimplemented() { + throw new RuntimeException("unimplemented"); + } + protected void setLuaPrototype(LPrototype lp) { this.p = lp; } @@ -22,17 +26,17 @@ public class JitPrototype extends LPrototype { return new JitClosure(this, env); } - private static final class JitClosure extends LClosure { + protected 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); + jp.jitCall(vm,env,this); return false; } } - public abstract void jitCall( LuaState vm, LTable env ); + public abstract void jitCall( LuaState vm, LTable env, JitClosure jcl ); } diff --git a/src/script/org/luaj/jit/LuaJit.java b/src/script/org/luaj/jit/LuaJit.java index b1ca389f..d184425b 100644 --- a/src/script/org/luaj/jit/LuaJit.java +++ b/src/script/org/luaj/jit/LuaJit.java @@ -19,6 +19,7 @@ import javax.tools.JavaCompiler.CompilationTask; import org.luaj.compiler.LuaC; import org.luaj.debug.Print; +import org.luaj.jit.JitPrototype.JitClosure; import org.luaj.platform.J2sePlatform; import org.luaj.vm.LClosure; import org.luaj.vm.LPrototype; @@ -99,26 +100,89 @@ public class LuaJit extends Lua { return p; } - + + private static String RKBC_jit(int bc) { + return LuaState.ISK(bc) ? + "k"+LuaState.INDEXK(bc): + "s"+bc; + } + + private static String GETARG_RKB_jit(int i) { + return RKBC_jit(GETARG_B(i)); + } + + private static String GETARG_RKC_jit(int i) { + return RKBC_jit(GETARG_C(i)); + } + private static void writeSource( PrintStream ps, String name, 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; + LValue i0, table; + boolean body; + String bs, cs; + + int[] code = p.code; + LValue[] k = p.k; + // class header ps.print( "import org.luaj.vm.*;\n"+ "import org.luaj.jit.*;\n"+ "\n"+ - "public class "+name+" extends JitPrototype {\n"+ - " public void jitCall(LuaState vm, LTable env) {\n"+ - " int base = vm.base;\n"+ - "" ); + "public class "+name+" extends JitPrototype {\n" ); - int[] code = p.code; - LValue[] k = p.k; - + // static constants + int nk = k.length; + if ( nk > 0 ) { + ps.print( "\tprivate LValue k0" ) ; + for (int ik=1; ik> POS_OP) & MAX_OP; + switch (o) { + case OP_FORPREP: + maxforlevels = Math.max(maxforlevels, ++forlevel); + break; + case OP_FORLOOP: + forlevel--; + break; + } + } + for ( int j=0; j> POS_A) & MAXARG_A; switch (o) { + default: + ps.println( "\t\tunimplemented();"); + break; case LuaState.OP_MOVE: { b = LuaState.GETARG_B(i); // this.stack[base + a] = this.stack[base + b]; - ps.println( "\t\tvm.stack[base+"+a+"] = vm.stack[base+"+b+"];" ); + ps.println( "\t\ts"+a+" = s"+b+";" ); continue; } case LuaState.OP_LOADK: { b = LuaState.GETARG_Bx(i); // this.stack[base + a] = k[b]; - ps.println( "\t\tvm.stack[base+"+a+"] = p.k["+b+"];" ); + ps.println( "\t\ts"+a+" = k"+b+";" ); continue; } /* @@ -157,75 +224,104 @@ public class LuaJit extends Lua { 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; + b = LuaState.GETARG_B(i); + ps.print("\t\t"); + for ( int j=a; j<=b; j++ ) + ps.print("s"+j+"="); + ps.println("LNil.NIL;"); + break; } case LuaState.OP_GETUPVAL: { - b = LuaState.GETARG_B(i); - this.stack[base + a] = cl.upVals[b].getValue(); - continue; + //b = LuaState.GETARG_B(i); + //this.stack[base + a] = cl.upVals[b].getValue(); + //continue; + b = LuaState.GETARG_B(i); + ps.println("\t\t\ts"+a+" = jcl.upVals["+b+"].getValue();"); + break; } - */ case LuaState.OP_GETGLOBAL: { - b = LuaState.GETARG_Bx(i); + // 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+";"); - ps.println("\t\tvm.top = "+a+";"); - ps.println("\t\tenv.luaGetTable(vm, env, p.k["+b+"]);"); - continue; + // continue + b = LuaState.GETARG_Bx(i); + ps.println("\t\tenv.luaGetTable(vm, env, k"+b+");"); + ps.println("\t\ts"+a+" = vm.stack[--vm.top];"); + break; } - /* 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; + //b = GETARG_B(i); + //key = GETARG_RKC(k, i); + //table = this.stack[base + b]; + //top = base + a; + //table.luaGetTable(this, table, key); + //continue; + b = GETARG_B(i); + cs = GETARG_RKC_jit(i); + ps.println("\t\ts"+b+".luaGetTable(vm, s"+b+", "+cs+");"); + ps.println("\t\ts"+a+" = vm.stack[--vm.top];"); + break; } 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; b = LuaState.GETARG_Bx(i); - key = k[b]; - val = this.stack[base + a]; - table = cl.env; - table.luaSetTable(this, table, key, val); - continue; + ps.println("\t\tenv.luaSetTable(vm, env, k"+b+", s"+a+");"); + break; } case LuaState.OP_SETUPVAL: { - b = LuaState.GETARG_B(i); - cl.upVals[b].setValue( this.stack[base + a] ); - continue; + //b = LuaState.GETARG_B(i); + //cl.upVals[b].setValue( this.stack[base + a] ); + //continue; + b = LuaState.GETARG_B(i); + ps.println("\t\t\tjcl.upVals["+b+"].setValue(s"+a+");"); + break; } 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; + //key = GETARG_RKB(k, i); + //val = GETARG_RKC(k, i); + //table = this.stack[base + a]; + //table.luaSetTable(this, table, key, val); + //continue; + bs = GETARG_RKB_jit(i); + cs = GETARG_RKC_jit(i); + ps.println("\t\ts"+a+".luaSetTable(vm, s"+a+", "+bs+", "+cs+");"); + break; } case LuaState.OP_NEWTABLE: { - b = LuaState.GETARG_B(i); - c = LuaState.GETARG_C(i); - this.stack[base + a] = new LTable(b, c); - continue; + //b = LuaState.GETARG_B(i); + //c = LuaState.GETARG_C(i); + //this.stack[base + a] = new LTable(b, c); + //continue; + b = GETARG_B(i); + c = GETARG_C(i); + ps.println("\t\ts"+a+" = new LTable("+b+","+c+");"); + break; } 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; + //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; + bs = GETARG_RKB_jit(i); + cs = GETARG_RKC_jit(i); + ps.println("\t\t"+bs+".luaGetTable(vm, "+bs+", "+cs+");"); + ps.println("\t\ts"+(a+1)+" = "+bs+";"); + break; } case LuaState.OP_ADD: case LuaState.OP_SUB: @@ -233,27 +329,39 @@ public class LuaJit extends Lua { 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; + //rkb = GETARG_RKB(k, i); + //rkc = GETARG_RKC(k, i); + //this.stack[base + a] = rkc.luaBinOpUnknown(o, rkb); + //continue; + bs = GETARG_RKB_jit(i); + cs = GETARG_RKC_jit(i); + ps.println("\t\ts"+a+" = "+cs+".luaBinOpUnknown("+o+","+bs+");"); + break; } case LuaState.OP_UNM: { - rkb = GETARG_RKB(k, i); - this.stack[base + a] = rkb.luaUnaryMinus(); - continue; + //rkb = GETARG_RKB(k, i); + //this.stack[base + a] = rkb.luaUnaryMinus(); + //continue; + bs = GETARG_RKB_jit(i); + ps.println("\t\ts"+a+" = "+bs+".luaUnaryMinus();"); } case LuaState.OP_NOT: { - rkb = GETARG_RKB(k, i); - this.stack[base + a] = (!rkb.toJavaBoolean() ? LBoolean.TRUE - : LBoolean.FALSE); - continue; + //rkb = GETARG_RKB(k, i); + //this.stack[base + a] = (!rkb.toJavaBoolean() ? LBoolean.TRUE + // : LBoolean.FALSE); + //continue; + bs = GETARG_RKB_jit(i); + ps.println("\t\ts"+a+" = ("+bs+".toJavaBoolean()? LBoolean.TRUE: LBoolean.FALSE);"); + break; } case LuaState.OP_LEN: { - rkb = GETARG_RKB(k, i); - this.stack[base + a] = LInteger.valueOf( rkb.luaLength() ); - continue; + //rkb = GETARG_RKB(k, i); + //this.stack[base + a] = LInteger.valueOf( rkb.luaLength() ); + //continue; + bs = GETARG_RKB_jit(i); + ps.println("\t\ts"+a+" = LInteger.valueOf("+bs+".luaLength());"); } + /* case LuaState.OP_CONCAT: { b = LuaState.GETARG_B(i); c = LuaState.GETARG_C(i); @@ -296,50 +404,57 @@ public class LuaJit extends Lua { } */ case LuaState.OP_CALL: { - - // ra is base of new call frame - // this.base += a; - // ps.println("\t\tvm.base = base+"+a+";"); - - // number of args - b = LuaState.GETARG_B(i); + // + //// 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; - // adjust top before the call - if (b != 0) { // else use previous instruction set top - // top = base + b; - ps.println("\t\tvm.top = "+(a+b)+";"); - } - - // number of return values we need - c = LuaState.GETARG_C(i); + // copy call to vm stack + ps.println( "\t\tvm.stack[base+"+a+"] = s"+a+";" ); + + // number of args + b = LuaState.GETARG_B(i); + if (b > 0) { // else use previous instruction set top + for ( int j=1; j 0. If call completed but -// // c == 0, leave top to point to end of results -// if (c > 0) { -// // adjustTop(base + c - 1); -// ps.println( "\t\tvm.settop("+nresults+");"); -// } -// -// // restore base -// // base = ci.base; -// -// // continue; - break; + // make the call + ps.println("\t\tvm.call("+(b-1)+","+(c-1)+");"); + + // copy results to local vars + if ( c > 0 ) + for ( int j=0; j= 0) - adjustTop(ci.resultbase + ci.nresults); - - // pop the call stack - --cc; - - // force a reload of the calling context - 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; + // number of return vals to return + + b = LuaState.GETARG_B(i); + if (b > 0) { + for ( int j=1; j=limit): (index<=limit); index+=step ) {"); - ps.println( "\t\tvm.stack[base+"+(a+3)+"] = LDouble.valueOf(index);"); + String init = "s"+(a); + String limit = "s"+(a+1); + String step = "s"+(a+2); + String idx = "s"+(a+3); + String back = "back"+(forlevel++); + ps.println( "\t\t"+back+"="+step+".luaBinCmpInteger(Lua.OP_LT,0);"); + ps.println( "\t\tfor ( "+idx+"="+init+";\n" + + "\t\t\t"+back+"? "+idx+".luaBinCmpUnknown(Lua.OP_LE, "+limit+"): "+limit+".luaBinCmpUnknown(Lua.OP_LE, "+idx+");\n" + + "\t\t\t"+idx+"="+idx+".luaBinOpUnknown(Lua.OP_ADD,"+step+") ) {"); + forlevel++; break; } case LuaState.OP_FORLOOP: { - ps.println( "\t\t}"); + forlevel--; + ps.println( "\t\t}"); //i0 = this.stack[base + a]; //step = this.stack[base + a + 2]; //idx = step.luaBinOpUnknown(Lua.OP_ADD, i0); @@ -444,8 +573,8 @@ public class LuaJit extends Lua { //continue; break; } + /* case LuaState.OP_TFORLOOP: { - ps.println( "\t\t}"); //cb = base + a + 3; // call base //base = cb; //adjustTop( cb + 3 ); @@ -467,7 +596,6 @@ public class LuaJit extends Lua { //} //continue; } - /* case LuaState.OP_SETLIST: { b = LuaState.GETARG_B(i); c = LuaState.GETARG_C(i); @@ -493,7 +621,7 @@ public class LuaJit extends Lua { case LuaState.OP_CLOSURE: { b = LuaState.GETARG_Bx(i); proto = cl.p.p[b]; - newClosure = new LClosure(proto, cl.env); + newClosure = proto.newClosure(cl.env); for (int j = 0; j < newClosure.upVals.length; j++, ci.pc++) { i = code[ci.pc]; o = LuaState.GET_OPCODE(i); diff --git a/src/script/org/luaj/jit/LuaJitTest.java b/src/script/org/luaj/jit/LuaJitTest.java new file mode 100644 index 00000000..a2d2ecd2 --- /dev/null +++ b/src/script/org/luaj/jit/LuaJitTest.java @@ -0,0 +1,19 @@ +package org.luaj.jit; +import java.io.IOException; + +import org.luaj.vm.LPrototype; +import org.luaj.vm.LuaJTest; +import org.luaj.vm.LuaState; + +/** + * Suite of standard tests, but using the LuaJit compiler + * for all loaded prototypes. + */ +public class LuaJitTest extends LuaJTest { + + protected LPrototype loadScriptResource( LuaState state, String name ) throws IOException { + LPrototype p = super.loadScriptResource(state, name); + return LuaJit.jitCompile(p); + } + +} diff --git a/src/script/org/luaj/script/LuaScriptEngine.java b/src/script/org/luaj/script/LuaScriptEngine.java index f4f539ce..1306721c 100644 --- a/src/script/org/luaj/script/LuaScriptEngine.java +++ b/src/script/org/luaj/script/LuaScriptEngine.java @@ -111,7 +111,7 @@ public class LuaScriptEngine extends LFunction implements ScriptEngine { LineNumberInputStream is = new LineNumberInputStream( bais ); try { LPrototype p = LoadState.undump(luaState, is, "script"); - LClosure c = new LClosure( p, luaState._G ); + LClosure c = p.newClosure( luaState._G ); luaState.doCall( c, new LValue[0] ); return luaState.topointer(1); } catch ( LuaErrorException lee ) { diff --git a/src/test/java/org/luaj/compiler/SimpleTests.java b/src/test/java/org/luaj/compiler/SimpleTests.java index f4664e6c..155d37fb 100644 --- a/src/test/java/org/luaj/compiler/SimpleTests.java +++ b/src/test/java/org/luaj/compiler/SimpleTests.java @@ -31,7 +31,7 @@ public class SimpleTests extends TestCase { // try running the code! LuaState state = Platform.newLuaState(); BaseLib.install( state._G ); - LClosure c = new LClosure( state, p ); + LClosure c = p.newClosure( state._G ); state.doCall( c, new LValue[0] ); } catch ( Exception e ) { fail("i/o exception: "+e ); diff --git a/src/test/java/org/luaj/debug/DebugStackStateTest.java b/src/test/java/org/luaj/debug/DebugStackStateTest.java index bad30226..86a204c8 100644 --- a/src/test/java/org/luaj/debug/DebugStackStateTest.java +++ b/src/test/java/org/luaj/debug/DebugStackStateTest.java @@ -55,7 +55,7 @@ public class DebugStackStateTest extends TestCase { LPrototype p = LoadState.undump(state, is, script); // create closure and execute - final LClosure c = new LClosure( state, p ); + final LClosure c = p.newClosure( state._G ); // suspend the vm right away state.suspend(); diff --git a/src/test/java/org/luaj/vm/LuaJTest.java b/src/test/java/org/luaj/vm/LuaJTest.java index 0dbd04da..740a688d 100644 --- a/src/test/java/org/luaj/vm/LuaJTest.java +++ b/src/test/java/org/luaj/vm/LuaJTest.java @@ -194,7 +194,7 @@ public class LuaJTest extends TestCase { BaseLib.redirectOutput( outputStream ); try { // create closure and execute - LClosure c = new LClosure( p, state._G ); + LClosure c = p.newClosure( state._G ); state.doCall(c, new LValue[0]); final String actualOutput = new String( outputStream.toByteArray() ); @@ -207,7 +207,7 @@ public class LuaJTest extends TestCase { } } - private LPrototype loadScriptResource( LuaState state, String name ) throws IOException { + protected LPrototype loadScriptResource( LuaState state, String name ) throws IOException { InputStream script = getClass().getResourceAsStream( "/"+name+".luac" ); if ( script == null ) { script = getClass().getResourceAsStream( "/"+name+".lua" ); diff --git a/src/test/java/org/luaj/vm/StandardTest.java b/src/test/java/org/luaj/vm/StandardTest.java index 077ed42d..bdabb0ae 100644 --- a/src/test/java/org/luaj/vm/StandardTest.java +++ b/src/test/java/org/luaj/vm/StandardTest.java @@ -74,7 +74,7 @@ public class StandardTest extends TestCase { // the garbage collector. Until we implement that, remove the // built-in collectgarbage function. state._G.put( "collectgarbage", LNil.NIL ); - LClosure c = new LClosure( code, state._G ); + LClosure c = code.newClosure( state._G ); ByteArrayOutputStream output = new ByteArrayOutputStream(); BaseLib.redirectOutput( output );