Update LuaJC to work with lua 5.2 model of environments.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user