From 7ae41da5e1f17456f6060cbccaa57ac3863eba20 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Sat, 8 Sep 2012 21:16:51 +0000 Subject: [PATCH] Update LuaJC to work with lua 5.2 model of environments. --- src/core/org/luaj/vm2/LuaClosure.java | 2 + src/core/org/luaj/vm2/LuaFunction.java | 9 ++- src/core/org/luaj/vm2/compiler/FuncState.java | 14 ++-- src/core/org/luaj/vm2/lib/VarArgFunction.java | 8 +- src/jse/org/luaj/vm2/luajc/JavaBuilder.java | 38 ++++++++-- src/jse/org/luaj/vm2/luajc/JavaGen.java | 76 +++++++------------ src/jse/org/luaj/vm2/luajc/ProtoInfo.java | 38 +++++----- src/jse/org/luaj/vm2/luajc/UpvalInfo.java | 8 +- 8 files changed, 105 insertions(+), 88 deletions(-) diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/src/core/org/luaj/vm2/LuaClosure.java index 365ca255..d11a0556 100644 --- a/src/core/org/luaj/vm2/LuaClosure.java +++ b/src/core/org/luaj/vm2/LuaClosure.java @@ -89,6 +89,8 @@ public class LuaClosure extends LuaFunction { private static final UpValue[] NOUPVALUES = new UpValue[0]; public final Prototype p; + + public UpValue[] upValues; /** Create a closure around a Prototype with the default global environment. * If the prototype has upvalues, the environment will be written into the first upvalue. diff --git a/src/core/org/luaj/vm2/LuaFunction.java b/src/core/org/luaj/vm2/LuaFunction.java index 541c63fc..7138d52f 100644 --- a/src/core/org/luaj/vm2/LuaFunction.java +++ b/src/core/org/luaj/vm2/LuaFunction.java @@ -38,8 +38,6 @@ public class LuaFunction extends LuaValue { /** Shared static metatable for all functions and closures. */ public static LuaValue s_metatable; - public UpValue[] upValues; - public int type() { return TFUNCTION; } @@ -64,8 +62,11 @@ public class LuaFunction extends LuaValue { return s_metatable; } + /** Hook for implementations such as LuaJC to load the environment of the main chunk + * into the first upvalue location. If the function has no upvalues or is not a main chunk, + * calling this will be no effect. + * @param env The environment to load into the first upvalue, if there is one. + */ public void initupvalue1(LuaValue env) { - if (upValues != null && upValues.length > 0) - upValues[0] = new UpValue(new LuaValue[] {env}, 0); } } diff --git a/src/core/org/luaj/vm2/compiler/FuncState.java b/src/core/org/luaj/vm2/compiler/FuncState.java index 89bdb13b..0e9188d7 100644 --- a/src/core/org/luaj/vm2/compiler/FuncState.java +++ b/src/core/org/luaj/vm2/compiler/FuncState.java @@ -474,20 +474,23 @@ public class FuncState extends LuaC { this.freereg(e.u.info); } + static final LuaUserdata NIL_PROXY = new LuaUserdata(LuaValue.NIL); + int addk(LuaValue v) { + LuaValue key = v.isnil()? NIL_PROXY: v; if (this.h == null) { this.h = new LuaTable(); } else { - LuaValue idx = this.h.get(v); + LuaValue idx = this.h.get(key); if (idx.isnumber()) return idx.toint(); } int idx = this.nk; - this.h.set(v, LuaValue.valueOf(idx)); + this.h.set(key, LuaValue.valueOf(idx)); final Prototype f = this.f; if (f.k == null || nk + 1 >= f.k.length) f.k = realloc( f.k, nk*2 + 1 ); - f.k[this.nk++] = v.isuserdata()? LuaValue.NIL: v; + f.k[this.nk++] = v; return idx; } @@ -509,11 +512,8 @@ public class FuncState extends LuaC { return this.addk((b ? LuaValue.TRUE : LuaValue.FALSE)); } - static final LuaUserdata NIL_PROXY = new LuaUserdata(LuaValue.NIL); - int nilK() { - /* cannot use nil as key; instead use table itself to represent nil */ - return this.addk(NIL_PROXY); + return this.addk(LuaValue.NIL); } void setreturns(expdesc e, int nresults) { diff --git a/src/core/org/luaj/vm2/lib/VarArgFunction.java b/src/core/org/luaj/vm2/lib/VarArgFunction.java index 42c78f80..1ceb5389 100644 --- a/src/core/org/luaj/vm2/lib/VarArgFunction.java +++ b/src/core/org/luaj/vm2/lib/VarArgFunction.java @@ -21,7 +21,6 @@ ******************************************************************************/ package org.luaj.vm2.lib; -import org.luaj.vm2.LuaThread; import org.luaj.vm2.LuaValue; import org.luaj.vm2.Varargs; @@ -77,6 +76,11 @@ abstract public class VarArgFunction extends LibFunction { * - function has a possibility of returning a TailcallVarargs * @param args the arguments to the function call. */ - abstract public Varargs invoke(Varargs args); + public Varargs invoke(Varargs args) { + return onInvoke(args).eval(); + } + public Varargs onInvoke(Varargs args) { + return invoke(args); + } } diff --git a/src/jse/org/luaj/vm2/luajc/JavaBuilder.java b/src/jse/org/luaj/vm2/luajc/JavaBuilder.java index b533de97..18c9c4ee 100644 --- a/src/jse/org/luaj/vm2/luajc/JavaBuilder.java +++ b/src/jse/org/luaj/vm2/luajc/JavaBuilder.java @@ -250,6 +250,7 @@ public class JavaBuilder { } // nil parameters + // TODO: remove this for lua 5.2, not needed for ( ; slot", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); - append(InstructionConstants.DUP); - loadEnv(); - append(factory.createInvoke(STR_LUAVALUE, "setfenv", Type.VOID, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL)); } public void closureInitUpvalueFromUpvalue(String protoname, int newup, int upindex) { @@ -779,4 +797,8 @@ public class JavaBuilder { public void tovalue() { append(factory.createInvoke(STR_BUFFER, "value", TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); } + + public void closeUpvalue(int pc, int i) { + // TODO: assign the upvalue location the value null; + } } diff --git a/src/jse/org/luaj/vm2/luajc/JavaGen.java b/src/jse/org/luaj/vm2/luajc/JavaGen.java index 398dfa78..f9c6ff8e 100644 --- a/src/jse/org/luaj/vm2/luajc/JavaGen.java +++ b/src/jse/org/luaj/vm2/luajc/JavaGen.java @@ -21,9 +21,9 @@ ******************************************************************************/ package org.luaj.vm2.luajc; -import org.luaj.vm2.Buffer; import org.luaj.vm2.Lua; import org.luaj.vm2.Prototype; +import org.luaj.vm2.Upvaldesc; /** * TODO: @@ -202,6 +202,11 @@ public class JavaGen { break; case Lua.OP_JMP: /* sBx pc+=sBx */ + if (a > 0) { + for (int i = a-1; i < pi.openups.length; ++i) { + builder.closeUpvalue(pc, i); + } + } builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx); break; @@ -228,7 +233,7 @@ public class JavaGen { builder.storeLocal( pc, a ); break; - case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */ + case Lua.OP_CALL: { /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */ // load function builder.loadLocal(pc, a); @@ -280,6 +285,7 @@ public class JavaGen { builder.storeVarresult(); break; } + } break; case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ @@ -343,45 +349,24 @@ public class JavaGen { break; case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ - throw new RuntimeException("Unimplemented OP_TFORCALL"); - - case Lua.OP_TFORLOOP: /* - * A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1), - * R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3) - * else pc++ - */ - // v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2])); - // if ( (o=v.arg1()).isnil() ) - // ++pc; builder.loadLocal(pc, a); builder.loadLocal(pc, a+1); builder.loadLocal(pc, a+2); - builder.invoke(2); // varresult on stack - builder.dup(); - builder.storeVarresult(); - builder.arg( 1 ); - builder.isNil(); - builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+2); - - // a[2] = a[3] = v[1], leave varargs on stack - builder.createUpvalues(pc, a+3, c); - builder.loadVarresult(); - if (c>=2) - builder.dup(); - builder.arg( 1 ); - builder.dup(); - builder.storeLocal(pc, a+2); - builder.storeLocal(pc, a+3); - - // v[2]..v[c], use varargs from stack - for ( int j=2; j<=c; j++ ) { - if ( j 0 ) builder.dup(); builder.storeLocal( pc, a ); - if ( nup > 0 ) { - for ( int up=0; up b0.pc0 ) propogateVars( v, pc-1, pc ); - int a,b,c,nups; + int a,b,c; int ins = prototype.code[pc]; int op = Lua.GET_OPCODE(ins); @@ -164,7 +167,6 @@ public class ProtoInfo { case Lua.OP_LOADK:/* A Bx R(A) := Kst(Bx) */ case Lua.OP_LOADBOOL:/* A B C R(A) := (Bool)B; if (C) pc++ */ case Lua.OP_GETUPVAL: /* A B R(A) := UpValue[B] */ - case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */ case Lua.OP_NEWTABLE: /* A B C R(A) := {} (size = B,C) */ a = Lua.GETARG_A( ins ); v[a][pc] = new VarInfo(a,pc); @@ -235,6 +237,13 @@ public class ProtoInfo { v[a][pc] = new VarInfo(a,pc); break; + case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */ + a = Lua.GETARG_A( ins ); + c = Lua.GETARG_C( ins ); + if (!Lua.ISK(c)) v[c][pc].isreferenced = true; + v[a][pc] = new VarInfo(a,pc); + break; + case Lua.OP_SELF: /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ a = Lua.GETARG_A( ins ); b = Lua.GETARG_B( ins ); @@ -316,22 +325,16 @@ public class ProtoInfo { v[a][pc] = VarInfo.INVALID; break; - case Lua.OP_CLOSURE: /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ + case Lua.OP_CLOSURE: { /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ a = Lua.GETARG_A( ins ); b = Lua.GETARG_Bx( ins ); - nups = prototype.p[b].upvalues.length; - for ( int k=1; k<=nups; ++k ) { - int i = prototype.code[pc+k]; - if ( (i&4) == 0 ) { - b = Lua.GETARG_B(i); - v[b][pc].isreferenced = true; - } - } + Upvaldesc[] upvalues = prototype.p[b].upvalues; + for (int k = 0, nups = upvalues.length; k < nups; ++k) + if (upvalues[k].instack) + v[upvalues[k].idx][pc].isreferenced = true; v[a][pc] = new VarInfo(a,pc); - for ( int k=1; k<=nups; k++ ) - propogateVars( v, pc, pc+k ); - pc += nups; break; + } case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */ a = Lua.GETARG_A( ins ); @@ -407,9 +410,8 @@ public class ProtoInfo { UpvalInfo[] newu = new UpvalInfo[newp.upvalues.length]; String newname = name + "$" + bx; for ( int j=0; j