Update LuaJC to work with lua 5.2 model of environments.

This commit is contained in:
James Roseborough
2012-09-08 21:16:51 +00:00
parent 09fc31aebc
commit 7ae41da5e1
8 changed files with 105 additions and 88 deletions

View File

@@ -90,6 +90,8 @@ public class LuaClosure extends LuaFunction {
public final Prototype p; public final Prototype p;
public UpValue[] upValues;
/** Create a closure around a Prototype with the default global environment. /** 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. * If the prototype has upvalues, the environment will be written into the first upvalue.
* @param p the Prototype to construct this Closure for. * @param p the Prototype to construct this Closure for.

View File

@@ -38,8 +38,6 @@ public class LuaFunction extends LuaValue {
/** Shared static metatable for all functions and closures. */ /** Shared static metatable for all functions and closures. */
public static LuaValue s_metatable; public static LuaValue s_metatable;
public UpValue[] upValues;
public int type() { public int type() {
return TFUNCTION; return TFUNCTION;
} }
@@ -64,8 +62,11 @@ public class LuaFunction extends LuaValue {
return s_metatable; 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) { public void initupvalue1(LuaValue env) {
if (upValues != null && upValues.length > 0)
upValues[0] = new UpValue(new LuaValue[] {env}, 0);
} }
} }

View File

@@ -474,20 +474,23 @@ public class FuncState extends LuaC {
this.freereg(e.u.info); this.freereg(e.u.info);
} }
static final LuaUserdata NIL_PROXY = new LuaUserdata(LuaValue.NIL);
int addk(LuaValue v) { int addk(LuaValue v) {
LuaValue key = v.isnil()? NIL_PROXY: v;
if (this.h == null) { if (this.h == null) {
this.h = new LuaTable(); this.h = new LuaTable();
} else { } else {
LuaValue idx = this.h.get(v); LuaValue idx = this.h.get(key);
if (idx.isnumber()) if (idx.isnumber())
return idx.toint(); return idx.toint();
} }
int idx = this.nk; int idx = this.nk;
this.h.set(v, LuaValue.valueOf(idx)); this.h.set(key, LuaValue.valueOf(idx));
final Prototype f = this.f; final Prototype f = this.f;
if (f.k == null || nk + 1 >= f.k.length) if (f.k == null || nk + 1 >= f.k.length)
f.k = realloc( f.k, nk*2 + 1 ); f.k = realloc( f.k, nk*2 + 1 );
f.k[this.nk++] = v.isuserdata()? LuaValue.NIL: v; f.k[this.nk++] = v;
return idx; return idx;
} }
@@ -509,11 +512,8 @@ public class FuncState extends LuaC {
return this.addk((b ? LuaValue.TRUE : LuaValue.FALSE)); return this.addk((b ? LuaValue.TRUE : LuaValue.FALSE));
} }
static final LuaUserdata NIL_PROXY = new LuaUserdata(LuaValue.NIL);
int nilK() { int nilK() {
/* cannot use nil as key; instead use table itself to represent nil */ return this.addk(LuaValue.NIL);
return this.addk(NIL_PROXY);
} }
void setreturns(expdesc e, int nresults) { void setreturns(expdesc e, int nresults) {

View File

@@ -21,7 +21,6 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2.lib; package org.luaj.vm2.lib;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
@@ -77,6 +76,11 @@ abstract public class VarArgFunction extends LibFunction {
* - function has a possibility of returning a TailcallVarargs * - function has a possibility of returning a TailcallVarargs
* @param args the arguments to the function call. * @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);
}
} }

View File

@@ -250,6 +250,7 @@ public class JavaBuilder {
} }
// nil parameters // nil parameters
// TODO: remove this for lua 5.2, not needed
for ( ; slot<p.maxstacksize; slot++ ) { for ( ; slot<p.maxstacksize; slot++ ) {
if ( pi.isInitialValueUsed(slot) ) { if ( pi.isInitialValueUsed(slot) ) {
loadNil(); loadNil();
@@ -280,6 +281,31 @@ public class JavaBuilder {
cg.addMethod(mg.getMethod()); cg.addMethod(mg.getMethod());
main.dispose(); main.dispose();
// add initupvalue1(LuaValue env) to initialize environment for main chunk
if (p.upvalues.length == 1 && superclassType == SUPERTYPE_VARARGS) {
MethodGen mg = new MethodGen( Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
Type.VOID, // return type
ARG_TYPES_LUAVALUE, // argument types
new String[] { "env" }, // arg names
"initupvalue1",
STR_LUAVALUE, // method, defining class
main, cp);
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[0] );
append(InstructionConstants.THIS);
append(new ALOAD(1));
if ( isrw ) {
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKESTATIC));
append(factory.createFieldAccess(classname, upvalueName(0), TYPE_LOCALUPVALUE, Constants.PUTFIELD));
} else {
append(factory.createFieldAccess(classname, upvalueName(0), TYPE_LUAVALUE, Constants.PUTFIELD));
}
append(InstructionConstants.RETURN);
mg.setMaxStack();
cg.addMethod(mg.getMethod());
main.dispose();
}
// convert to class bytes // convert to class bytes
try { try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -420,11 +446,6 @@ public class JavaBuilder {
append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, ARG_TYPES_INT_INT, Constants.INVOKESTATIC)); append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, ARG_TYPES_INT_INT, Constants.INVOKESTATIC));
} }
public void loadEnv() {
append(InstructionConstants.THIS);
append(factory.createFieldAccess(classname, "env", TYPE_LUAVALUE, Constants.GETFIELD));
}
public void loadVarargs() { public void loadVarargs() {
append(new ALOAD(1)); append(new ALOAD(1));
} }
@@ -594,9 +615,6 @@ public class JavaBuilder {
append(factory.createNew(new ObjectType(protoname))); append(factory.createNew(new ObjectType(protoname)));
append(InstructionConstants.DUP); append(InstructionConstants.DUP);
append(factory.createInvoke(protoname, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); append(factory.createInvoke(protoname, "<init>", 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) { public void closureInitUpvalueFromUpvalue(String protoname, int newup, int upindex) {
@@ -779,4 +797,8 @@ public class JavaBuilder {
public void tovalue() { public void tovalue() {
append(factory.createInvoke(STR_BUFFER, "value", TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); 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;
}
} }

View File

@@ -21,9 +21,9 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2.luajc; package org.luaj.vm2.luajc;
import org.luaj.vm2.Buffer;
import org.luaj.vm2.Lua; import org.luaj.vm2.Lua;
import org.luaj.vm2.Prototype; import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
/** /**
* TODO: * TODO:
@@ -202,6 +202,11 @@ public class JavaGen {
break; break;
case Lua.OP_JMP: /* sBx pc+=sBx */ 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); builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
break; break;
@@ -228,7 +233,7 @@ public class JavaGen {
builder.storeLocal( pc, a ); builder.storeLocal( pc, a );
break; 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 // load function
builder.loadLocal(pc, a); builder.loadLocal(pc, a);
@@ -280,6 +285,7 @@ public class JavaGen {
builder.storeVarresult(); builder.storeVarresult();
break; break;
} }
}
break; break;
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ 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; break;
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ 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);
builder.loadLocal(pc, a+1); builder.loadLocal(pc, a+1);
builder.loadLocal(pc, a+2); builder.loadLocal(pc, a+2);
builder.invoke(2); // varresult on stack builder.invoke(2);
for ( int i=1; i<=c; i++ ) {
if ( i < c )
builder.dup(); builder.dup();
builder.storeVarresult(); builder.arg( i );
builder.arg( 1 ); builder.storeLocal(pc, a+2+i);
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<c )
builder.dup();
builder.arg( j );
builder.storeLocal(pc, a+2+j);
} }
break; break;
case Lua.OP_TFORLOOP:/* A sBx if R(A) != nil then ps+= sBx */
builder.loadLocal(pc, a);
builder.isNil();
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
break;
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */ case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1; int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1;
builder.loadLocal( pc, a ); builder.loadLocal( pc, a );
@@ -401,25 +386,20 @@ public class JavaGen {
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)) */
{ {
Prototype newp = p.p[bx]; Prototype newp = p.p[bx];
String protoname = closureName(classname, bx);
int nup = newp.upvalues.length; int nup = newp.upvalues.length;
String protoname = closureName(classname, bx);
builder.closureCreate( protoname ); builder.closureCreate( protoname );
if ( nup > 0 ) if ( nup > 0 )
builder.dup(); builder.dup();
builder.storeLocal( pc, a ); builder.storeLocal( pc, a );
if ( nup > 0 ) {
for ( int up=0; up<nup; ++up ) { for ( int up=0; up<nup; ++up ) {
if ( up+1 < nup ) if ( up+1 < nup )
builder.dup(); builder.dup();
ins = p.code[pc+up+1]; Upvaldesc u = newp.upvalues[up];
b = Lua.GETARG_B(ins); if (u.instack)
if ( (ins&4) != 0 ) { builder.closureInitUpvalueFromLocal( protoname, up, pc, u.idx );
builder.closureInitUpvalueFromUpvalue( protoname, up, b ); else
} else { builder.closureInitUpvalueFromUpvalue( protoname, up, u.idx );
builder.closureInitUpvalueFromLocal( protoname, up, pc, b );
}
}
pc += nup;
} }
break; break;
} }

View File

@@ -6,6 +6,7 @@ import java.io.PrintStream;
import org.luaj.vm2.Lua; import org.luaj.vm2.Lua;
import org.luaj.vm2.Print; import org.luaj.vm2.Print;
import org.luaj.vm2.Prototype; import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
/** /**
* Prototype information for static single-assignment analysis * Prototype information for static single-assignment analysis
@@ -22,8 +23,10 @@ public class ProtoInfo {
public final UpvalInfo[] upvals; // from outer scope public final UpvalInfo[] upvals; // from outer scope
public final UpvalInfo[][] openups; // per slot, upvalues allocated by this prototype public final UpvalInfo[][] openups; // per slot, upvalues allocated by this prototype
// A main chunk proto info.
public ProtoInfo(Prototype p, String name) { public ProtoInfo(Prototype p, String name) {
this(p,name,null); // For the outer chunk, we have one upvalue which is the environment.
this(p,name,new UpvalInfo[] { new UpvalInfo() });
} }
private ProtoInfo(Prototype p, String name, UpvalInfo[] u) { private ProtoInfo(Prototype p, String name, UpvalInfo[] u) {
@@ -155,7 +158,7 @@ public class ProtoInfo {
if ( pc > b0.pc0 ) if ( pc > b0.pc0 )
propogateVars( v, pc-1, pc ); propogateVars( v, pc-1, pc );
int a,b,c,nups; int a,b,c;
int ins = prototype.code[pc]; int ins = prototype.code[pc];
int op = Lua.GET_OPCODE(ins); 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_LOADK:/* A Bx R(A) := Kst(Bx) */
case Lua.OP_LOADBOOL:/* A B C R(A) := (Bool)B; if (C) pc++ */ 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_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) */ case Lua.OP_NEWTABLE: /* A B C R(A) := {} (size = B,C) */
a = Lua.GETARG_A( ins ); a = Lua.GETARG_A( ins );
v[a][pc] = new VarInfo(a,pc); v[a][pc] = new VarInfo(a,pc);
@@ -235,6 +237,13 @@ public class ProtoInfo {
v[a][pc] = new VarInfo(a,pc); v[a][pc] = new VarInfo(a,pc);
break; 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)] */ case Lua.OP_SELF: /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
a = Lua.GETARG_A( ins ); a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins ); b = Lua.GETARG_B( ins );
@@ -316,22 +325,16 @@ public class ProtoInfo {
v[a][pc] = VarInfo.INVALID; v[a][pc] = VarInfo.INVALID;
break; 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 ); a = Lua.GETARG_A( ins );
b = Lua.GETARG_Bx( ins ); b = Lua.GETARG_Bx( ins );
nups = prototype.p[b].upvalues.length; Upvaldesc[] upvalues = prototype.p[b].upvalues;
for ( int k=1; k<=nups; ++k ) { for (int k = 0, nups = upvalues.length; k < nups; ++k)
int i = prototype.code[pc+k]; if (upvalues[k].instack)
if ( (i&4) == 0 ) { v[upvalues[k].idx][pc].isreferenced = true;
b = Lua.GETARG_B(i);
v[b][pc].isreferenced = true;
}
}
v[a][pc] = new VarInfo(a,pc); v[a][pc] = new VarInfo(a,pc);
for ( int k=1; k<=nups; k++ )
propogateVars( v, pc, pc+k );
pc += nups;
break; break;
}
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */ case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
a = Lua.GETARG_A( ins ); a = Lua.GETARG_A( ins );
@@ -407,9 +410,8 @@ public class ProtoInfo {
UpvalInfo[] newu = new UpvalInfo[newp.upvalues.length]; UpvalInfo[] newu = new UpvalInfo[newp.upvalues.length];
String newname = name + "$" + bx; String newname = name + "$" + bx;
for ( int j=0; j<newp.upvalues.length; ++j ) { for ( int j=0; j<newp.upvalues.length; ++j ) {
int i = code[++pc]; Upvaldesc u = newp.upvalues[j];
int b = Lua.GETARG_B(i); newu[j] = u.instack? findOpenUp(pc,u.idx) : upvals[u.idx];
newu[j] = (i&4) != 0? upvals[b]: findOpenUp(pc,b);
} }
subprotos[bx] = new ProtoInfo(newp, newname, newu); subprotos[bx] = new ProtoInfo(newp, newname, newu);
} }

View File

@@ -12,6 +12,12 @@ public class UpvalInfo {
VarInfo var[]; // list of vars VarInfo var[]; // list of vars
boolean rw; // read-write boolean rw; // read-write
// Upval info representing the implied context containing only the environment.
public UpvalInfo() {
nvars = 1;
var = new VarInfo[] { VarInfo.PARAM(0) };
}
public UpvalInfo(ProtoInfo pi, int pc, int slot) { public UpvalInfo(ProtoInfo pi, int pc, int slot) {
this.pi = pi; this.pi = pi;
this.slot = slot; this.slot = slot;