diff --git a/src/addon/java/lua/addon/luajava/CoerceLuaToJava.java b/src/addon/java/lua/addon/luajava/CoerceLuaToJava.java index 17a00e34..9552b32e 100644 --- a/src/addon/java/lua/addon/luajava/CoerceLuaToJava.java +++ b/src/addon/java/lua/addon/luajava/CoerceLuaToJava.java @@ -3,7 +3,7 @@ package lua.addon.luajava; import java.util.HashMap; import java.util.Map; -import lua.StackState; +import lua.CallFrame; import lua.addon.luajava.LuaJava.LInstance; import lua.value.LBoolean; import lua.value.LDouble; @@ -105,11 +105,11 @@ public class CoerceLuaToJava { return v; } - static Object[] coerceArgs(StackState state, int base, int nargs, Class[] parameterTypes) { + static Object[] coerceArgs(CallFrame call, int base, int nargs, Class[] parameterTypes) { int n = parameterTypes.length; Object[] args = new Object[n]; for ( int i=0; i= 0) - state.adjustTop(base + nresults); + call.adjustTop(base + nresults); } - static class LInstance extends LValue { + public static class LInstance extends LValue { Object instance; private Class clazz; public LInstance(Object o, Class clazz) { @@ -106,29 +106,29 @@ public final class LuaJava extends LFunction { public String luaAsString() { return instance.toString(); } - public void luaGetTable(StackState state, int base, LValue table, LValue key) { + public void luaGetTable(CallFrame call, int base, LValue table, LValue key) { final String s = key.luaAsString(); try { Field f = clazz.getField(s); Object o = f.get(instance); LValue v = CoerceJavaToLua.coerce( o ); - state.stack[base] = v; - state.top = base + 1; + call.stack[base] = v; + call.top = base + 1; } catch (NoSuchFieldException nsfe) { - state.stack[base] = new LMethod(instance,clazz,s); - state.top = base + 1; + call.stack[base] = new LMethod(instance,clazz,s); + call.top = base + 1; } catch (Exception e) { throw new RuntimeException(e); } } - public void luaSetTable(StackState state, int base, LValue table, LValue key, LValue val) { + public void luaSetTable(CallFrame call, int base, LValue table, LValue key, LValue val) { Class c = instance.getClass(); String s = key.luaAsString(); try { Field f = c.getField(s); Object v = CoerceLuaToJava.coerceArg(val, f.getType()); f.set(instance,v); - state.top = base; + call.top = base; } catch (Exception e) { throw new RuntimeException(e); } @@ -148,7 +148,7 @@ public final class LuaJava extends LFunction { public String toString() { return clazz.getName()+"."+s+"()"; } - public void luaStackCall(StackState state, int base, int top, int nresults) { + public void luaStackCall(CallFrame call, int base, int top, int nresults) { try { Method[] meths = clazz.getMethods(); Method meth = null; @@ -161,7 +161,7 @@ public final class LuaJava extends LFunction { String name = m.getName(); if ( s.equals(name) ) { Class[] p = m.getParameterTypes(); - int s = CoerceLuaToJava.scoreParamTypes( state.stack, paramsBase, nargs, p ); + int s = CoerceLuaToJava.scoreParamTypes( call.stack, paramsBase, nargs, p ); if ( s < score ) { meth = m; paramTypes = p; @@ -169,11 +169,11 @@ public final class LuaJava extends LFunction { } } } - Object[] args = CoerceLuaToJava.coerceArgs( state, paramsBase, nargs, paramTypes ); + Object[] args = CoerceLuaToJava.coerceArgs( call, paramsBase, nargs, paramTypes ); Object result = meth.invoke( instance, args ); - state.stack[base] = CoerceJavaToLua.coerce(result); - state.top = base + 1; - state.adjustTop(base+nresults); + call.stack[base] = CoerceJavaToLua.coerce(result); + call.top = base + 1; + call.adjustTop(base+nresults); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/src/main/java/lua/Builtin.java b/src/main/java/lua/Builtin.java index b869e046..56c26f4c 100644 --- a/src/main/java/lua/Builtin.java +++ b/src/main/java/lua/Builtin.java @@ -12,7 +12,7 @@ final class Builtin extends LFunction { static void addBuiltins(LTable table) { for ( int i=0; i= 0) - state.adjustTop(base + nresults); + call.adjustTop(base + nresults); } } \ No newline at end of file diff --git a/src/main/java/lua/CallFrame.java b/src/main/java/lua/CallFrame.java new file mode 100644 index 00000000..d40f93ff --- /dev/null +++ b/src/main/java/lua/CallFrame.java @@ -0,0 +1,431 @@ +/** + * + */ +package lua; + +import lua.io.Closure; +import lua.io.Proto; +import lua.value.LBoolean; +import lua.value.LInteger; +import lua.value.LNil; +import lua.value.LString; +import lua.value.LTable; +import lua.value.LValue; + +public class CallFrame { + private final static boolean DEBUG = false; + + public final StackState state; + public final LValue[] stack; + public int base; + public int top; + private final Closure cl; + private final Proto p; + private final LValue[] k; + private final int nresults; + private int pc = 0; + boolean done = false; + + CallFrame(StackState state, Closure c, int base, int nargs, int nresults) { + this.state = state; + this.stack = state.stack; + this.cl = c; + this.p = c.p; + this.k = p.k; + this.base = base; + this.nresults = nresults; + int nparams = p.numparams; + int nvalues = (p.is_vararg && nargs > nparams ? nargs : nparams); + for (int i = nargs; i < nvalues; i++) + this.state.stack[base + i] = LNil.NIL; + this.top = base + nvalues; + this.state.calls[++this.state.cc] = this; + this.state.avail = base + p.maxstacksize; + } + + private LValue RKBC(int bc) { + return StackState.ISK(bc) ? k[StackState.INDEXK(bc)] + : this.state.stack[base + bc]; + } + + private LValue GETARG_RKB(int i) { + return RKBC(StackState.GETARG_B(i)); + } + + private LValue GETARG_RKC(int i) { + return RKBC(StackState.GETARG_C(i)); + } + + public void adjustTop(int newTop) { + while (top < newTop) + this.stack[top++] = LNil.NIL; + top = newTop; + } + + public void exec() { + int i, a, b, c, o, n, cb; + LValue rkb, rkc, nvarargs, key, val; + StringBuffer sb; + LValue i0, step, idx, limit, init, table; + boolean back, body; + Proto proto; + Closure newClosure; + + // reload the current calling context + int[] code = p.code; + state.avail = base + p.maxstacksize; + while (true) { + + if (DEBUG) + Print.printState(state, base, top, state.avail, cl, pc); + + i = code[pc++]; + + // TODO: implement debug hooks + // if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && + // (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { + // traceexec(L, pc); + // if (L->status == LUA_YIELD) { // did hook yield? + // L->savedpc = pc - 1; + // return; + // } + // base = L->base; + // } + + a = StackState.GETARG_A(i); + switch (StackState.GET_OPCODE(i)) { + case StackState.OP_MOVE: { + b = StackState.GETARG_B(i); + this.stack[base + a] = this.stack[base + b]; + continue; + } + case StackState.OP_LOADK: { + b = StackState.GETARG_Bx(i); + this.stack[base + a] = k[b]; + continue; + } + case StackState.OP_LOADBOOL: { + b = StackState.GETARG_B(i); + c = StackState.GETARG_C(i); + this.stack[base + a] = (b != 0 ? LBoolean.TRUE + : LBoolean.FALSE); + if (c != 0) + pc++; /* skip next instruction (if C) */ + continue; + } + case StackState.OP_LOADNIL: { + b = StackState.GETARG_B(i); + do { + this.stack[base + b] = LNil.NIL; + } while ((--b) >= a); + continue; + } + case StackState.OP_GETUPVAL: { + b = StackState.GETARG_B(i); + this.stack[base + a] = cl.upVals[b].value; + continue; + } + case StackState.OP_GETGLOBAL: { + b = StackState.GETARG_Bx(i); + key = k[b]; + table = cl.env; + table.luaGetTable(this, base + a, table, key); + continue; + } + case StackState.OP_GETTABLE: { + b = StackState.GETARG_B(i); + key = GETARG_RKC(i); + table = this.stack[base + b]; + table.luaGetTable(this, base + a, table, key); + continue; + } + case StackState.OP_SETGLOBAL: { + b = StackState.GETARG_Bx(i); + key = k[b]; + val = this.stack[base + a]; + table = cl.env; + table.luaSetTable(this, this.state.avail, table, key, val); + continue; + } + case StackState.OP_SETUPVAL: { + b = StackState.GETARG_B(i); + cl.upVals[b].value = this.stack[base + a]; + continue; + } + case StackState.OP_SETTABLE: { + key = GETARG_RKB(i); + val = GETARG_RKC(i); + table = this.stack[base + a]; + table.luaSetTable(this, state.avail, table, key, val); + continue; + } + case StackState.OP_NEWTABLE: { + b = StackState.GETARG_B(i); + c = StackState.GETARG_C(i); + this.stack[base + a] = new LTable(b, c); + continue; + } + case StackState.OP_SELF: { + rkb = GETARG_RKB(i); + rkc = GETARG_RKC(i); + this.stack[base + a + 1] = rkb; + rkb.luaGetTable(this, base + a, rkb, rkc); + // StkId rb = RB(i); + // setobjs2s(L, ra+1, rb); + // Protect(luaV_gettable(L, rb, RKC(i), ra)); + continue; + } + case StackState.OP_ADD: + case StackState.OP_SUB: + case StackState.OP_MUL: + case StackState.OP_DIV: + case StackState.OP_MOD: + case StackState.OP_POW: { + o = StackState.GET_OPCODE(i); + rkb = GETARG_RKB(i); + rkc = GETARG_RKC(i); + this.stack[base + a] = rkc.luaBinOpUnknown(o, rkb); + continue; + } + case StackState.OP_UNM: { + rkb = GETARG_RKB(i); + this.stack[base + a] = rkb.luaUnaryMinus(); + continue; + } + case StackState.OP_NOT: { + rkb = GETARG_RKB(i); + this.stack[base + a] = (rkb.luaAsBoolean() ? LBoolean.TRUE + : LBoolean.FALSE); + continue; + } + case StackState.OP_LEN: { + rkb = GETARG_RKB(i); + this.stack[base + a] = rkb.luaLength(); + continue; + } + case StackState.OP_CONCAT: { + b = StackState.GETARG_B(i); + c = StackState.GETARG_C(i); + sb = new StringBuffer(); + for (int j = b; j <= c; j++) + sb.append(this.stack[base + j].luaAsString()); + this.stack[base + a] = new LString(sb.toString()); + continue; + } + case StackState.OP_JMP: { + pc += StackState.GETARG_sBx(i); + continue; + } + case StackState.OP_EQ: + case StackState.OP_LT: + case StackState.OP_LE: { + o = StackState.GET_OPCODE(i); + rkb = GETARG_RKB(i); + rkc = GETARG_RKC(i); + boolean test = rkc.luaBinCmpUnknown(o, rkb); + if (test) + pc++; + continue; + } + case StackState.OP_TEST: { + c = StackState.GETARG_C(i); + if (this.stack[base + a].luaAsBoolean() != (c != 0)) + pc++; + continue; + } + case StackState.OP_TESTSET: { + rkb = GETARG_RKB(i); + c = StackState.GETARG_C(i); + if (rkb.luaAsBoolean() != (c != 0)) + pc++; + else + this.stack[base + a] = rkb; + continue; + } + case StackState.OP_CALL: { + /* ra is start of result location */ + b = StackState.GETARG_B(i); // number of stack spaces to reserve + // for + // closure plus args + c = StackState.GETARG_C(i); // num results plus 1 + if (b != 0) // else use previous instruction set top + top = base + a + b; + + // make or set up the call + this.stack[base + a].luaStackCall(this, base + a, top, c - 1); + + // force re-entry into current call + if (this.state.calls[this.state.cc] != this) + return; + + // adjustTop only for case when call was completed + if (c > 0) + adjustTop(base + a + c - 1); + + continue; + } + case StackState.OP_TAILCALL: { + b = StackState.GETARG_B(i); // number of stack spaces to reserve + // for + // closure plus args ?? + c = StackState.GETARG_C(i); // number of return args - must be + // LUA_MULTRET + if (b != 0) // else use previous instruction set top + top = base + a + b; + + // make or set up the call + this.stack[base + a].luaStackCall(this, base + a, top, c - 1); + + // adjustTop only for case when call was completed + if (this.state.calls[this.state.cc] != this) { + // was a vm call, or a Java call that re-entered the stack. + // copy down the stack variables and substitute the stack + // frame. + CallFrame ci = this.state.calls[this.state.cc]; + n = ci.top - ci.base; + System.arraycopy(this.stack, ci.base, + this.stack, base, n); + ci.base = base; + ci.top = base + n; + this.state.calls[this.state.cc - 1] = this.state.calls[this.state.cc]; + --this.state.cc; + + // force a reset of the calling context state + return; + } + continue; + } + case StackState.OP_RETURN: { + b = StackState.GETARG_B(i); // number of return vals + if (b != 0) // else use previous top + top = base + a + b - 1; + n = top - (base + a); // number to copy down + System.arraycopy(this.stack, base + a, this.stack, + base - 1, n); + top = base - 1 + n; + + // adjust results to what caller expected + if (nresults >= 0) + adjustTop(base + nresults); + + // pop the call stack + done = true; + if ( --state.cc >= 0 ) + state.calls[state.cc].top = top; + + // force a reload of the calling context + return; + } + case StackState.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; + pc += StackState.GETARG_sBx(i); + } + continue; + } + case StackState.OP_FORPREP: { + init = this.stack[base + a]; + step = this.stack[base + a + 2]; + this.stack[base + a] = step.luaBinOpUnknown(Lua.OP_SUB, + init); + b = StackState.GETARG_sBx(i); + pc += b; + continue; + } + case StackState.OP_TFORLOOP: { + cb = a + 3; /* call base */ + System.arraycopy(this.stack, base + a, this.stack, + base + cb, 3); + top = base + cb + 3; /* func. + 2 args (state and index) */ + + // call the iterator + c = StackState.GETARG_C(i); + this.stack[base + a].luaStackCall(this, base + cb, top, c - 1); + + // test for continuation + if (this.stack[base + cb] != LNil.NIL) { // continue? + this.stack[base + cb - 1] = this.stack[base + + cb]; // save control variable + } else { + pc++; // skip over jump + } + continue; + } + case StackState.OP_SETLIST: { + b = StackState.GETARG_B(i); + c = StackState.GETARG_C(i); + if (b == 0) { + b = top - 1; + } + if (c == 0) { + c = code[pc++]; + } + table = this.stack[base + a]; + for (int index = 1; index <= b; index++) { + val = this.stack[base + a + index]; + table.luaSetTable(this, this.state.avail, table, + new LInteger(index), val); + } + top = base + a - 1; + continue; + } + case StackState.OP_CLOSE: { + // for java, no need to do anything! + continue; + } + case StackState.OP_CLOSURE: { + b = StackState.GETARG_Bx(i); + proto = cl.p.p[b]; + newClosure = new Closure(this.state, proto); + for (int j = 0; j < newClosure.upVals.length; j++, pc++) { + i = code[pc]; + o = StackState.GET_OPCODE(i); + b = StackState.GETARG_B(i); + if (o == StackState.OP_GETUPVAL) { + newClosure.upVals[j] = cl.upVals[b]; // TODO + } else if (o == StackState.OP_MOVE) { + newClosure.upVals[j].value = this.stack[base + b]; // TODO: + // what + // to do + // here? + } else { + throw new java.lang.IllegalArgumentException( + "bad opcode: " + o); + } + } + this.stack[base + a] = newClosure; + continue; + } + case StackState.OP_VARARG: { + // figure out how many args to copy + b = StackState.GETARG_B(i) - 1; + nvarargs = this.stack[base - 1]; + n = nvarargs.luaAsInt(); + if (b == StackState.LUA_MULTRET) { + b = n; // use entire varargs supplied + } + + // copy args up to call stack area + 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; + } + } + } + } + + public void push(LValue value) { + stack[top++] = value; + } +} \ No newline at end of file diff --git a/src/main/java/lua/GlobalState.java b/src/main/java/lua/GlobalState.java index 12ca7553..84723cf0 100644 --- a/src/main/java/lua/GlobalState.java +++ b/src/main/java/lua/GlobalState.java @@ -2,7 +2,6 @@ package lua; import java.util.Hashtable; -import lua.value.LString; import lua.value.LTable; /** @@ -11,27 +10,10 @@ import lua.value.LTable; public class GlobalState { // typedef struct global_State { -// stringtable strt; /* hash table for strings */ Hashtable strt; /* hash table for strings */ -// lua_Alloc frealloc; /* function to reallocate memory */ -// void *ud; /* auxiliary data to `frealloc' */ -// lu_byte currentwhite; -// lu_byte gcstate; /* state of garbage collector */ -// int sweepstrgc; /* position of sweep in `strt' */ -// GCObject *rootgc; /* list of all collectable objects */ -// GCObject **sweepgc; /* position of sweep in `rootgc' */ -// GCObject *gray; /* list of gray objects */ -// GCObject *grayagain; /* list of objects to be traversed atomically */ -// GCObject *weak; /* list of weak tables (to be cleared) */ -// GCObject *tmudata; /* last element of list of userdata to be GC */ -// Mbuffer buff; /* temporary buffer for string concatentation */ StringBuffer buff; /* temporary buffer for string concatentation */ -// lu_mem GCthreshold; // lu_mem totalbytes; /* number of bytes currently allocated */ // lu_mem estimate; /* an estimate of number of bytes actually in use */ -// lu_mem gcdept; /* how much GC is `behind schedule' */ -// int gcpause; /* size of pause between successive GCs */ -// int gcstepmul; /* GC `granularity' */ // lua_CFunction panic; /* to be called in unprotected errors */ // TValue l_registry; // struct lua_State *mainthread; @@ -45,8 +27,8 @@ public class GlobalState { static { _G = new LTable(); + _G .put( "_G", _G ); Builtin.addBuiltins( _G ); - _G .m_hash.put(new LString("_G"), _G ); } public static LTable getGlobalsTable() { diff --git a/src/main/java/lua/io/Closure.java b/src/main/java/lua/io/Closure.java index e2495c28..231fc06c 100644 --- a/src/main/java/lua/io/Closure.java +++ b/src/main/java/lua/io/Closure.java @@ -1,5 +1,6 @@ package lua.io; +import lua.CallFrame; import lua.StackState; import lua.value.LFunction; import lua.value.LValue; @@ -9,7 +10,7 @@ public class Closure extends LFunction { public Proto p; public UpVal[] upVals; public Closure(StackState state, Proto p) { - this.env = state.gt(); + this.env = state._G; this.p = p; upVals = new UpVal[p.nups]; for ( int i=0; i= 0 ) - state.adjustTop(base + nresults); + call.adjustTop(base + nresults); } } diff --git a/src/main/java/lua/value/LValue.java b/src/main/java/lua/value/LValue.java index 85348c84..3f64b176 100644 --- a/src/main/java/lua/value/LValue.java +++ b/src/main/java/lua/value/LValue.java @@ -1,7 +1,7 @@ package lua.value; +import lua.CallFrame; import lua.Lua; -import lua.StackState; abstract public class LValue { @@ -20,7 +20,7 @@ public class LValue { } // perform a lua call, return number of results actually produced - public void luaStackCall(StackState state, int base, int top, int nresults) { + public void luaStackCall(CallFrame call, int base, int top, int nresults) { luaUnsupportedOperation(); } @@ -72,20 +72,20 @@ public class LValue { } /** set a value in a table - * @param state the stack state + * @param call the stack state * @param base the base of the stack, in case a function is put on the stack * @param table the table to operate on * @param the key to set * @param the value to set */ - public void luaSetTable(StackState state, int base, LValue table, LValue key, LValue val) { + public void luaSetTable(CallFrame call, int base, LValue table, LValue key, LValue val) { luaUnsupportedOperation(); } /** Get a value from a table * @param base TODO * @param table TODO*/ - public void luaGetTable(StackState state, int base, LValue table, LValue key) { + public void luaGetTable(CallFrame call, int base, LValue table, LValue key) { luaUnsupportedOperation(); } diff --git a/src/test/java/LuaJavaAppRunner.java b/src/test/java/LuaJavaAppRunner.java index aff73468..0df09d0c 100644 --- a/src/test/java/LuaJavaAppRunner.java +++ b/src/test/java/LuaJavaAppRunner.java @@ -2,13 +2,13 @@ import java.io.IOException; import java.io.InputStream; -import lua.GlobalState; import lua.StackState; import lua.addon.luajava.LuaJava; import lua.io.Closure; import lua.io.LoadState; import lua.io.Proto; import lua.value.LString; +import lua.value.LValue; /** * Program to run a compiled lua chunk for test purposes, @@ -30,20 +30,18 @@ public class LuaJavaAppRunner { // new lua state StackState state = new StackState(); - // push args onto stack + // convert args to lua + LValue[] vargs = new LValue[args.length]; for ( int i=1; i= 4 ) then + i = 0 + end + i = i + 1 return table[i] end @@ -76,5 +77,4 @@ function room4 () end room1() ---]] \ No newline at end of file diff --git a/src/test/res/test2.luac b/src/test/res/test2.luac index 9e6d15f4..0febd6a6 100644 Binary files a/src/test/res/test2.luac and b/src/test/res/test2.luac differ diff --git a/src/test/res/test7.lua b/src/test/res/test7.lua index f249083e..c109e778 100644 --- a/src/test/res/test7.lua +++ b/src/test/res/test7.lua @@ -5,7 +5,7 @@ obj = luajava.newInstance("SampleClass") print( obj ) obj.s = "Hello" print( obj.s ) -print( obj.getS() ) +print( obj:getS() ) -obj.setS( "World" ) +obj:setS( "World" ) print( obj.s ) diff --git a/src/test/res/test7.luac b/src/test/res/test7.luac index 0f29cd35..00cff7a3 100644 Binary files a/src/test/res/test7.luac and b/src/test/res/test7.luac differ