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

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -250,6 +250,7 @@ public class JavaBuilder {
}
// nil parameters
// TODO: remove this for lua 5.2, not needed
for ( ; slot<p.maxstacksize; slot++ ) {
if ( pi.isInitialValueUsed(slot) ) {
loadNil();
@@ -279,7 +280,32 @@ public class JavaBuilder {
mg.setMaxStack();
cg.addMethod(mg.getMethod());
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
try {
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));
}
public void loadEnv() {
append(InstructionConstants.THIS);
append(factory.createFieldAccess(classname, "env", TYPE_LUAVALUE, Constants.GETFIELD));
}
public void loadVarargs() {
append(new ALOAD(1));
}
@@ -594,9 +615,6 @@ public class JavaBuilder {
append(factory.createNew(new ObjectType(protoname)));
append(InstructionConstants.DUP);
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) {
@@ -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;
}
}

View File

@@ -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<c )
builder.invoke(2);
for ( int i=1; i<=c; i++ ) {
if ( i < c )
builder.dup();
builder.arg( j );
builder.storeLocal(pc, a+2+j);
builder.arg( i );
builder.storeLocal(pc, a+2+i);
}
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 */
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1;
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)) */
{
Prototype newp = p.p[bx];
String protoname = closureName(classname, bx);
int nup = newp.upvalues.length;
String protoname = closureName(classname, bx);
builder.closureCreate( protoname );
if ( nup > 0 )
builder.dup();
builder.storeLocal( pc, a );
if ( nup > 0 ) {
for ( int up=0; up<nup; ++up ) {
if ( up+1 < nup )
builder.dup();
ins = p.code[pc+up+1];
b = Lua.GETARG_B(ins);
if ( (ins&4) != 0 ) {
builder.closureInitUpvalueFromUpvalue( protoname, up, b );
} else {
builder.closureInitUpvalueFromLocal( protoname, up, pc, b );
}
}
pc += nup;
for ( int up=0; up<nup; ++up ) {
if ( up+1 < nup )
builder.dup();
Upvaldesc u = newp.upvalues[up];
if (u.instack)
builder.closureInitUpvalueFromLocal( protoname, up, pc, u.idx );
else
builder.closureInitUpvalueFromUpvalue( protoname, up, u.idx );
}
break;
}

View File

@@ -6,6 +6,7 @@ import java.io.PrintStream;
import org.luaj.vm2.Lua;
import org.luaj.vm2.Print;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
/**
* Prototype information for static single-assignment analysis
@@ -22,8 +23,10 @@ public class ProtoInfo {
public final UpvalInfo[] upvals; // from outer scope
public final UpvalInfo[][] openups; // per slot, upvalues allocated by this prototype
// A main chunk proto info.
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) {
@@ -155,7 +158,7 @@ public class ProtoInfo {
if ( pc > 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<newp.upvalues.length; ++j ) {
int i = code[++pc];
int b = Lua.GETARG_B(i);
newu[j] = (i&4) != 0? upvals[b]: findOpenUp(pc,b);
Upvaldesc u = newp.upvalues[j];
newu[j] = u.instack? findOpenUp(pc,u.idx) : upvals[u.idx];
}
subprotos[bx] = new ProtoInfo(newp, newname, newu);
}

View File

@@ -11,7 +11,13 @@ public class UpvalInfo {
int nvars; // number of vars involved
VarInfo var[]; // list of vars
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) {
this.pi = pi;
this.slot = slot;