First cut at updating compiler and runtime to handle lua 5.2 bytecodes. Able to compile and execute "hello, world" lua script.

This commit is contained in:
James Roseborough
2012-08-23 04:40:40 +00:00
parent 659a20a999
commit f7e17c588e
19 changed files with 792 additions and 557 deletions

View File

@@ -141,6 +141,7 @@ public class LoadState {
private static final Prototype[] NOPROTOS = {}; private static final Prototype[] NOPROTOS = {};
private static final LocVars[] NOLOCVARS = {}; private static final LocVars[] NOLOCVARS = {};
private static final LuaString[] NOSTRVALUES = {}; private static final LuaString[] NOSTRVALUES = {};
private static final Upvaldesc[] NOUPVALDESCS = {};
private static final int[] NOINTS = {}; private static final int[] NOINTS = {};
/** Read buffer */ /** Read buffer */
@@ -282,12 +283,24 @@ public class LoadState {
f.p = protos; f.p = protos;
} }
void loadUpvalues(Prototype f) throws IOException {
int n = loadInt();
f.upvalues = n>0? new Upvaldesc[n]: NOUPVALDESCS;
for (int i=0; i<n; i++) {
boolean instack = is.readByte() != 0;
int idx = ((int) is.readByte()) & 0xff;
f.upvalues[i] = new Upvaldesc(null, instack, idx);
}
}
/** /**
* Load the debug infor for a function prototype * Load the debug info for a function prototype
* @param f the function Prototype * @param f the function Prototype
* @throws IOException if there is an i/o exception * @throws IOException if there is an i/o exception
*/ */
void loadDebug( Prototype f ) throws IOException { void loadDebug( Prototype f ) throws IOException {
f.source = loadString();
f.lineinfo = loadIntArray(); f.lineinfo = loadIntArray();
int n = loadInt(); int n = loadInt();
f.locvars = n>0? new LocVars[n]: NOLOCVARS; f.locvars = n>0? new LocVars[n]: NOLOCVARS;
@@ -299,10 +312,9 @@ public class LoadState {
} }
n = loadInt(); n = loadInt();
f.upvalues = n>0? new LuaString[n]: NOSTRVALUES; f.upvalues = n>0? new Upvaldesc[n]: NOUPVALDESCS;
for ( int i=0; i<n; i++ ) { for ( int i=0; i<n; i++ )
f.upvalues[i] = loadString(); f.upvalues[i] = new Upvaldesc(loadString(), false, i);
}
} }
/** /**
@@ -319,12 +331,12 @@ public class LoadState {
f.source = p; f.source = p;
f.linedefined = loadInt(); f.linedefined = loadInt();
f.lastlinedefined = loadInt(); f.lastlinedefined = loadInt();
f.nups = is.readUnsignedByte();
f.numparams = is.readUnsignedByte(); f.numparams = is.readUnsignedByte();
f.is_vararg = is.readUnsignedByte(); f.is_vararg = is.readUnsignedByte();
f.maxstacksize = is.readUnsignedByte(); f.maxstacksize = is.readUnsignedByte();
f.code = loadIntArray(); f.code = loadIntArray();
loadConstants(f); loadConstants(f);
loadUpvalues(f);
loadDebug(f); loadDebug(f);
// TODO: add check here, for debugging purposes, I believe // TODO: add check here, for debugging purposes, I believe

View File

@@ -22,7 +22,7 @@
package org.luaj.vm2; package org.luaj.vm2;
/** /**
* Data class to hold debug information relatign to local variables for a {@link Prototype} * Data class to hold debug information relating to local variables for a {@link Prototype}
*/ */
public class LocVars { public class LocVars {
/** The local variable name */ /** The local variable name */

View File

@@ -64,6 +64,7 @@ public class Lua {
public static final int iABC = 0; public static final int iABC = 0;
public static final int iABx = 1; public static final int iABx = 1;
public static final int iAsBx = 2; public static final int iAsBx = 2;
public static final int iAx = 3;
/* /*
@@ -73,6 +74,7 @@ public class Lua {
public static final int SIZE_B = 9; public static final int SIZE_B = 9;
public static final int SIZE_Bx = (SIZE_C + SIZE_B); public static final int SIZE_Bx = (SIZE_C + SIZE_B);
public static final int SIZE_A = 8; public static final int SIZE_A = 8;
public static final int SIZE_Ax = (SIZE_C + SIZE_B + SIZE_A);
public static final int SIZE_OP = 6; public static final int SIZE_OP = 6;
@@ -81,6 +83,7 @@ public class Lua {
public static final int POS_C = (POS_A + SIZE_A); public static final int POS_C = (POS_A + SIZE_A);
public static final int POS_B = (POS_C + SIZE_C); public static final int POS_B = (POS_C + SIZE_C);
public static final int POS_Bx = POS_C; public static final int POS_Bx = POS_C;
public static final int POS_Ax = POS_A;
public static final int MAX_OP = ((1<<SIZE_OP)-1); public static final int MAX_OP = ((1<<SIZE_OP)-1);
@@ -89,6 +92,7 @@ public class Lua {
public static final int MAXARG_C = ((1<<SIZE_C)-1); public static final int MAXARG_C = ((1<<SIZE_C)-1);
public static final int MAXARG_Bx = ((1<<SIZE_Bx)-1); public static final int MAXARG_Bx = ((1<<SIZE_Bx)-1);
public static final int MAXARG_sBx = (MAXARG_Bx>>1); /* `sBx' is signed */ public static final int MAXARG_sBx = (MAXARG_Bx>>1); /* `sBx' is signed */
public static final int MAXARG_Ax = ((1<<SIZE_Ax)-1);
public static final int MASK_OP = ((1<<SIZE_OP)-1)<<POS_OP; public static final int MASK_OP = ((1<<SIZE_OP)-1)<<POS_OP;
public static final int MASK_A = ((1<<SIZE_A)-1)<<POS_A; public static final int MASK_A = ((1<<SIZE_A)-1)<<POS_A;
@@ -113,6 +117,10 @@ public class Lua {
return (i >> POS_A) & MAXARG_A; return (i >> POS_A) & MAXARG_A;
} }
public static int GETARG_Ax(int i) {
return (i >> POS_Ax) & MAXARG_Ax;
}
public static int GETARG_B(int i) { public static int GETARG_B(int i) {
return (i >> POS_B) & MAXARG_B; return (i >> POS_B) & MAXARG_B;
} }
@@ -177,59 +185,62 @@ public class Lua {
------------------------------------------------------------------------*/ ------------------------------------------------------------------------*/
public static final int OP_MOVE = 0;/* A B R(A) := R(B) */ public static final int OP_MOVE = 0;/* A B R(A) := R(B) */
public static final int OP_LOADK = 1;/* A Bx R(A) := Kst(Bx) */ public static final int OP_LOADK = 1;/* A Bx R(A) := Kst(Bx) */
public static final int OP_LOADBOOL = 2;/* A B C R(A) := (Bool)B; if (C) pc++ */ public static final int OP_LOADKX = 2;/* A R(A) := Kst(extra arg) */
public static final int OP_LOADNIL = 3; /* A B R(A) := ... := R(B) := nil */ public static final int OP_LOADBOOL = 3;/* A B C R(A) := (Bool)B; if (C) pc++ */
public static final int OP_GETUPVAL = 4; /* A B R(A) := UpValue[B] */ public static final int OP_LOADNIL = 4; /* A B R(A) := ... := R(B) := nil */
public static final int OP_GETUPVAL = 5; /* A B R(A) := UpValue[B] */
public static final int OP_GETGLOBAL = 5; /* A Bx R(A) := Gbl[Kst(Bx)] */ public static final int OP_GETTABUP = 6; /* A B C R(A) := UpValue[B][RK(C)] */
public static final int OP_GETTABLE = 6; /* A B C R(A) := R(B)[RK(C)] */ public static final int OP_GETTABLE = 7; /* A B C R(A) := R(B)[RK(C)] */
public static final int OP_SETGLOBAL = 7; /* A Bx Gbl[Kst(Bx)] := R(A) */ public static final int OP_SETTABUP = 8; /* A B C UpValue[A][RK(B)] := RK(C) */
public static final int OP_SETUPVAL = 8; /* A B UpValue[B] := R(A) */ public static final int OP_SETUPVAL = 9; /* A B UpValue[B] := R(A) */
public static final int OP_SETTABLE = 9; /* A B C R(A)[RK(B)] := RK(C) */ public static final int OP_SETTABLE = 10; /* A B C R(A)[RK(B)] := RK(C) */
public static final int OP_NEWTABLE = 10; /* A B C R(A) := {} (size = B,C) */ public static final int OP_NEWTABLE = 11; /* A B C R(A) := {} (size = B,C) */
public static final int OP_SELF = 11; /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ public static final int OP_SELF = 12; /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
public static final int OP_ADD = 12; /* A B C R(A) := RK(B) + RK(C) */ public static final int OP_ADD = 13; /* A B C R(A) := RK(B) + RK(C) */
public static final int OP_SUB = 13; /* A B C R(A) := RK(B) - RK(C) */ public static final int OP_SUB = 14; /* A B C R(A) := RK(B) - RK(C) */
public static final int OP_MUL = 14; /* A B C R(A) := RK(B) * RK(C) */ public static final int OP_MUL = 15; /* A B C R(A) := RK(B) * RK(C) */
public static final int OP_DIV = 15; /* A B C R(A) := RK(B) / RK(C) */ public static final int OP_DIV = 16; /* A B C R(A) := RK(B) / RK(C) */
public static final int OP_MOD = 16; /* A B C R(A) := RK(B) % RK(C) */ public static final int OP_MOD = 17; /* A B C R(A) := RK(B) % RK(C) */
public static final int OP_POW = 17; /* A B C R(A) := RK(B) ^ RK(C) */ public static final int OP_POW = 18; /* A B C R(A) := RK(B) ^ RK(C) */
public static final int OP_UNM = 18; /* A B R(A) := -R(B) */ public static final int OP_UNM = 19; /* A B R(A) := -R(B) */
public static final int OP_NOT = 19; /* A B R(A) := not R(B) */ public static final int OP_NOT = 20; /* A B R(A) := not R(B) */
public static final int OP_LEN = 20; /* A B R(A) := length of R(B) */ public static final int OP_LEN = 21; /* A B R(A) := length of R(B) */
public static final int OP_CONCAT = 21; /* A B C R(A) := R(B).. ... ..R(C) */ public static final int OP_CONCAT = 22; /* A B C R(A) := R(B).. ... ..R(C) */
public static final int OP_JMP = 22; /* sBx pc+=sBx */ public static final int OP_JMP = 23; /* sBx pc+=sBx */
public static final int OP_EQ = 24; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
public static final int OP_LT = 25; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
public static final int OP_LE = 26; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
public static final int OP_EQ = 23; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ public static final int OP_TEST = 27; /* A C if not (R(A) <=> C) then pc++ */
public static final int OP_LT = 24; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ public static final int OP_TESTSET = 28; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
public static final int OP_LE = 25; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
public static final int OP_TEST = 26; /* A C if not (R(A) <=> C) then pc++ */ public static final int OP_CALL = 29; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
public static final int OP_TESTSET = 27; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ public static final int OP_TAILCALL = 30; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
public static final int OP_RETURN = 31; /* A B return R(A), ... ,R(A+B-2) (see note) */
public static final int OP_CALL = 28; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ public static final int OP_FORLOOP = 32; /* A sBx R(A)+=R(A+2);
public static final int OP_TAILCALL = 29; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
public static final int OP_RETURN = 30; /* A B return R(A), ... ,R(A+B-2) (see note) */
public static final int OP_FORLOOP = 31; /* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/ if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
public static final int OP_FORPREP = 32; /* A sBx R(A)-=R(A+2); pc+=sBx */ public static final int OP_FORPREP = 33; /* A sBx R(A)-=R(A+2); pc+=sBx */
public static final int OP_TFORLOOP = 33; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); public static final int OP_TFORCALL = 34; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
public static final int OP_TFORLOOP = 35; /* 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++ */ if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */
public static final int OP_SETLIST = 34; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ public static final int OP_SETLIST = 36; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
public static final int OP_CLOSE = 35; /* A close all variables in the stack up to (>=) R(A)*/ public static final int OP_CLOSURE = 37; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
public static final int OP_CLOSURE = 36; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
public static final int OP_VARARG = 37; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
public static final int NUM_OPCODES = OP_VARARG + 1; public static final int OP_VARARG = 38; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
public static final int OP_EXTRAARG = 39; /* Ax extra (larger) argument for previous opcode */
public static final int NUM_OPCODES = OP_EXTRAARG + 1;
/* pseudo-opcodes used in parsing only. */ /* pseudo-opcodes used in parsing only. */
public static final int OP_GT = 63; // > public static final int OP_GT = 63; // >
@@ -277,12 +288,13 @@ public class Lua {
/* T A B C mode opcode */ /* T A B C mode opcode */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_MOVE */ (0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_MOVE */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_LOADK */ (0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_LOADK */
(0<<7) | (1<<6) | (OpArgN<<4) | (OpArgN<<2) | (iABx), /* OP_LOADKX */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_LOADBOOL */ (0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_LOADBOOL */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_LOADNIL */ (0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_LOADNIL */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_GETUPVAL */ (0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_GETUPVAL */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_GETGLOBAL */ (0<<7) | (1<<6) | (OpArgU<<4) | (OpArgK<<2) | (iABC), /* OP_GETTABUP */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgK<<2) | (iABC), /* OP_GETTABLE */ (0<<7) | (1<<6) | (OpArgR<<4) | (OpArgK<<2) | (iABC), /* OP_GETTABLE */
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_SETGLOBAL */ (0<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SETTABUP */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_SETUPVAL */ (0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_SETUPVAL */
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SETTABLE */ (0<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SETTABLE */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_NEWTABLE */ (0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_NEWTABLE */
@@ -301,18 +313,19 @@ public class Lua {
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_EQ */ (1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_EQ */
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LT */ (1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LT */
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LE */ (1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LE */
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgU<<2) | (iABC), /* OP_TEST */ (1<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TEST */
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgU<<2) | (iABC), /* OP_TESTSET */ (1<<7) | (1<<6) | (OpArgR<<4) | (OpArgU<<2) | (iABC), /* OP_TESTSET */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_CALL */ (0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_CALL */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_TAILCALL */ (0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_TAILCALL */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_RETURN */ (0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_RETURN */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORLOOP */ (0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORLOOP */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORPREP */ (0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORPREP */
(1<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TFORLOOP */ (0<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TFORCALL */
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_TFORLOOP */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_SETLIST */ (0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_SETLIST */
(0<<7) | (0<<6) | (OpArgN<<4) | (OpArgN<<2) | (iABC), /* OP_CLOSE */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABx), /* OP_CLOSURE */ (0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABx), /* OP_CLOSURE */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_VARARG */ (0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_VARARG */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iAx), /* OP_EXTRAARG */
}; };
public static int getOpMode(int m) { public static int getOpMode(int m) {

View File

@@ -21,9 +21,6 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.luaj.vm2.LoadState.LuaCompiler; import org.luaj.vm2.LoadState.LuaCompiler;
import org.luaj.vm2.compiler.LuaC; import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.DebugLib; import org.luaj.vm2.lib.DebugLib;
@@ -101,15 +98,17 @@ public class LuaClosure extends LuaFunction {
} }
/** Supply the initial environment */ /** Supply the initial environment */
public LuaClosure(Prototype p, LuaValue env) { public LuaClosure(Prototype p, LuaValue env) {
super( env ); this(p, p.upvalues.length, env);
this.p = p;
this.upValues = p.nups>0? new UpValue[p.nups]: NOUPVALUES;
} }
protected LuaClosure(int nupvalues, LuaValue env) { protected LuaClosure(Prototype p, int nupvalues, LuaValue env) {
super( env ); super( env );
this.p = null; this.p = p;
this.upValues = nupvalues>0? new UpValue[nupvalues]: NOUPVALUES; switch (nupvalues) {
case 0: this.upValues = NOUPVALUES; break;
case 1: this.upValues = new UpValue[] { new UpValue(new LuaValue[1], 0) }; this.upValues[0].setValue(env); break;
default: this.upValues = new UpValue[nupvalues]; break;
}
} }
public boolean isclosure() { public boolean isclosure() {
@@ -233,16 +232,16 @@ public class LuaClosure extends LuaFunction {
stack[a] = upValues[i>>>23].getValue(); stack[a] = upValues[i>>>23].getValue();
continue; continue;
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */ case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
stack[a] = env.get(k[i>>>14]); stack[a] = upValues[i>>>23].getValue().get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */ case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */ case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
env.set(k[i>>>14], stack[a]); upValues[a].getValue().set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */ case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
@@ -423,6 +422,10 @@ public class LuaClosure extends LuaFunction {
} }
continue; continue;
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
continue;
case Lua.OP_TFORLOOP: /* case Lua.OP_TFORLOOP: /*
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1), * 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) * R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
@@ -462,21 +465,12 @@ public class LuaClosure extends LuaFunction {
} }
continue; continue;
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
for ( b=openups.length; --b>=a; )
if ( openups[b]!=null ) {
openups[b].close();
openups[b] = null;
}
continue;
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[i>>>14]; Prototype newp = p.p[i>>>14];
LuaClosure newcl = new LuaClosure(newp, env); LuaClosure newcl = new LuaClosure(newp, env);
for ( int j=0, nup=newp.nups; j<nup; ++j ) { for ( int j=0, nup=newp.upvalues.length; j<nup; ++j ) {
i = code[pc++]; i = code[pc++];
//b = B(i);
b = i>>>23; b = i>>>23;
newcl.upValues[j] = (i&4) != 0? newcl.upValues[j] = (i&4) != 0?
upValues[b]: upValues[b]:
@@ -496,6 +490,12 @@ public class LuaClosure extends LuaFunction {
stack[a+j-1] = varargs.arg(j); stack[a+j-1] = varargs.arg(j);
} }
continue; continue;
case Lua.OP_EXTRAARG:
throw new java.lang.IllegalArgumentException("Uexecutable opcode: OP_EXTRAARG");
default:
throw new java.lang.IllegalArgumentException("Illegal opcode: " + (i & 0x3f));
} }
} }
} catch ( LuaError le ) { } catch ( LuaError le ) {

View File

@@ -188,6 +188,8 @@ public class LuaValue extends Varargs {
/** LuaValue array constant with no values */ /** LuaValue array constant with no values */
public static final LuaValue[] NOVALS = {}; public static final LuaValue[] NOVALS = {};
/** The variable name of the environment. */
public static LuaString ENV = valueOf("_ENV");
/** LuaString constant with value "__index" for use as metatag */ /** LuaString constant with value "__index" for use as metatag */
public static final LuaString INDEX = valueOf("__index"); public static final LuaString INDEX = valueOf("__index");

View File

@@ -136,6 +136,11 @@ public class Print extends Lua {
printValue( ps, f.k[i] ); printValue( ps, f.k[i] );
} }
static void printUpvalue(PrintStream ps, Upvaldesc u) {
ps.print( u.idx + " " );
printValue( ps, u.name );
}
/** /**
* Print the code in a prototype * Print the code in a prototype
* @param f the {@link Prototype} * @param f the {@link Prototype}
@@ -211,12 +216,12 @@ public class Print extends Lua {
case OP_SETUPVAL: case OP_SETUPVAL:
ps.print(" ; "); ps.print(" ; ");
if ( f.upvalues.length > b ) if ( f.upvalues.length > b )
printValue(ps, f.upvalues[b]); printUpvalue(ps, f.upvalues[b]);
else else
ps.print( "-" ); ps.print( "-" );
break; break;
case OP_GETGLOBAL: case OP_GETTABUP:
case OP_SETGLOBAL: case OP_SETTABUP:
ps.print(" ; "); ps.print(" ; ");
printConstant( ps, f, bx ); printConstant( ps, f, bx );
break; break;

View File

@@ -42,10 +42,9 @@ public class Prototype {
public int[] lineinfo; public int[] lineinfo;
/* information about local variables */ /* information about local variables */
public LocVars[] locvars; public LocVars[] locvars;
/* upvalue names */ /* upvalue information */
public LuaString[] upvalues; public Upvaldesc[] upvalues;
public LuaString source; public LuaString source;
public int nups;
public int linedefined; public int linedefined;
public int lastlinedefined; public int lastlinedefined;
public int numparams; public int numparams;

View File

@@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (c) 2012 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2;
public class Upvaldesc {
/* upvalue name (for debug information) */
public final LuaString name;
/* whether it is in stack */
public final boolean instack;
/* index of upvalue (in stack or in outer function's list) */
public final short idx;
public Upvaldesc(LuaString name, boolean instack, int idx) {
this.name = name;
this.instack = instack;
this.idx = (short) idx;
}
}

View File

@@ -178,13 +178,23 @@ public class DumpState {
dumpFunction(f.p[i], f.source); dumpFunction(f.p[i], f.source);
} }
void dumpUpvalues(final Prototype f) throws IOException {
int n = f.upvalues.length;
dumpInt(n);
for (int i = 0; i < n; i++) {
writer.writeByte(f.upvalues[i].instack ? 1 : 0);
writer.writeByte(f.upvalues[i].idx);
}
}
void dumpDebug(final Prototype f) throws IOException { void dumpDebug(final Prototype f) throws IOException {
int i, n; int i, n;
n = (strip) ? 0 : f.lineinfo.length; dumpString(strip ? null: f.source);
n = strip ? 0 : f.lineinfo.length;
dumpInt(n); dumpInt(n);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
dumpInt(f.lineinfo[i]); dumpInt(f.lineinfo[i]);
n = (strip) ? 0 : f.locvars.length; n = strip ? 0 : f.locvars.length;
dumpInt(n); dumpInt(n);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
LocVars lvi = f.locvars[i]; LocVars lvi = f.locvars[i];
@@ -192,10 +202,10 @@ public class DumpState {
dumpInt(lvi.startpc); dumpInt(lvi.startpc);
dumpInt(lvi.endpc); dumpInt(lvi.endpc);
} }
n = (strip) ? 0 : f.upvalues.length; n = strip ? 0 : f.upvalues.length;
dumpInt(n); dumpInt(n);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
dumpString(f.upvalues[i]); dumpString(f.upvalues[i].name);
} }
void dumpFunction(final Prototype f, final LuaString string) throws IOException { void dumpFunction(final Prototype f, final LuaString string) throws IOException {
@@ -205,12 +215,12 @@ public class DumpState {
dumpString(f.source); dumpString(f.source);
dumpInt(f.linedefined); dumpInt(f.linedefined);
dumpInt(f.lastlinedefined); dumpInt(f.lastlinedefined);
dumpChar(f.nups);
dumpChar(f.numparams); dumpChar(f.numparams);
dumpChar(f.is_vararg); dumpChar(f.is_vararg);
dumpChar(f.maxstacksize); dumpChar(f.maxstacksize);
dumpCode(f); dumpCode(f);
dumpConstants(f); dumpConstants(f);
dumpUpvalues(f);
dumpDebug(f); dumpDebug(f);
} }

View File

@@ -21,15 +21,15 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2.compiler; package org.luaj.vm2.compiler;
import java.util.Hashtable;
import org.luaj.vm2.LuaBoolean; import org.luaj.vm2.LuaBoolean;
import org.luaj.vm2.LuaDouble; import org.luaj.vm2.LuaDouble;
import org.luaj.vm2.LuaInteger; import org.luaj.vm2.LuaInteger;
import org.luaj.vm2.LocVars; import org.luaj.vm2.LocVars;
import org.luaj.vm2.Lua; import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaNil; import org.luaj.vm2.LuaNil;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.Prototype; import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.compiler.LexState.ConsControl; import org.luaj.vm2.compiler.LexState.ConsControl;
@@ -37,22 +37,18 @@ import org.luaj.vm2.compiler.LexState.expdesc;
public class FuncState extends LuaC { public class FuncState extends LuaC {
class upvaldesc {
short k;
short info;
};
static class BlockCnt { static class BlockCnt {
BlockCnt previous; /* chain */ BlockCnt previous; /* chain */
IntPtr breaklist = new IntPtr(); /* list of jumps out of this loop */ short firstlabel; /* index of first label in this block */
short firstgoto; /* index of first pending goto in this block */
short nactvar; /* # active locals outside the breakable structure */ short nactvar; /* # active locals outside the breakable structure */
boolean upval; /* true if some variable in the block is an upvalue */ boolean upval; /* true if some variable in the block is an upvalue */
boolean isbreakable; /* true if `block' is a loop */ boolean isloop; /* true if `block' is a loop */
}; };
Prototype f; /* current function header */ Prototype f; /* current function header */
// LTable h; /* table to find (and reuse) elements in `k' */ LuaTable h; /* table to find (and reuse) elements in `k' */
Hashtable htable; /* table to find (and reuse) elements in `k' */
FuncState prev; /* enclosing function */ FuncState prev; /* enclosing function */
LexState ls; /* lexical state */ LexState ls; /* lexical state */
LuaC L; /* compiler being invoked */ LuaC L; /* compiler being invoked */
@@ -60,13 +56,13 @@ public class FuncState extends LuaC {
int pc; /* next position to code (equivalent to `ncode') */ int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* `pc' of last `jump target' */ int lasttarget; /* `pc' of last `jump target' */
IntPtr jpc; /* list of pending jumps to `pc' */ IntPtr jpc; /* list of pending jumps to `pc' */
int freereg; /* first free register */
int nk; /* number of elements in `k' */ int nk; /* number of elements in `k' */
int np; /* number of elements in `p' */ int np; /* number of elements in `p' */
int firstlocal; /* index of first local var (in Dyndata array) */
short nlocvars; /* number of elements in `locvars' */ short nlocvars; /* number of elements in `locvars' */
short nactvar; /* number of active local variables */ short nactvar; /* number of active local variables */
upvaldesc upvalues[] = new upvaldesc[LUAI_MAXUPVALUES]; /* upvalues */ short nups; /* number of upvalues */
short actvar[] = new short[LUAI_MAXVARS]; /* declared-variable stack */ short freereg; /* first free register */
FuncState() { FuncState() {
} }
@@ -77,11 +73,11 @@ public class FuncState extends LuaC {
// ============================================================= // =============================================================
InstructionPtr getcodePtr(expdesc e) { InstructionPtr getcodePtr(expdesc e) {
return new InstructionPtr( f.code, e.u.s.info ); return new InstructionPtr( f.code, e.u.info );
} }
int getcode(expdesc e) { int getcode(expdesc e) {
return f.code[e.u.s.info]; return f.code[e.u.info];
} }
int codeAsBx(int o, int A, int sBx) { int codeAsBx(int o, int A, int sBx) {
@@ -97,9 +93,18 @@ public class FuncState extends LuaC {
// from lparser.c // from lparser.c
// ============================================================= // =============================================================
LocVars getlocvar(int i) { /* check for repeated labels on the same block */
return f.locvars[actvar[i]]; void checkrepeated (LexState.Labeldesc[] ll, int ll_n, LuaString label) {
int i;
for (i = bl.firstlabel; i < ll_n; i++) {
if (label.eq_b(ll[i].name)) {
String msg = ls.L.pushfstring(
"label '" + label + " already defined on line " + ll[i].line);
ls.semerror(msg);
} }
}
}
void checklimit(int v, int l, String msg) { void checklimit(int v, int l, String msg) {
if ( v > l ) if ( v > l )
@@ -107,37 +112,47 @@ public class FuncState extends LuaC {
} }
void errorlimit (int limit, String what) { void errorlimit (int limit, String what) {
// TODO: report message logic.
String msg = (f.linedefined == 0) ? String msg = (f.linedefined == 0) ?
L.pushfstring("main function has more than "+limit+" "+what) : L.pushfstring("main function has more than "+limit+" "+what) :
L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what); L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
ls.lexerror(msg, 0); ls.lexerror(msg, 0);
} }
LocVars getlocvar(int i) {
int idx = ls.dyd.actvar[firstlocal + i].idx;
_assert(idx < nlocvars);
return f.locvars[idx];
}
int indexupvalue(LuaString name, expdesc v) { void removevars (int tolevel) {
ls.dyd.n_actvar -= (nactvar - tolevel);
while (nactvar > tolevel)
getlocvar(--nactvar).endpc = pc;
}
int searchupvalue (LuaString name) {
int i; int i;
for (i = 0; i < f.nups; i++) { Upvaldesc[] up = f.upvalues;
if (upvalues[i].k == v.k && upvalues[i].info == v.u.s.info) { for (i = 0; i < nups; i++)
_assert(f.upvalues[i] == name); if (up[i].name.eq_b(name))
return i; return i;
return -1; /* not found */
} }
}
/* new one */ int newupvalue (LuaString name, expdesc v) {
checklimit(f.nups + 1, LUAI_MAXUPVALUES, "upvalues"); checklimit(nups + 1, LUAI_MAXUPVAL, "upvalues");
if ( f.upvalues == null || f.nups + 1 > f.upvalues.length) if (f.upvalues == null || nups + 1 > f.upvalues.length)
f.upvalues = realloc( f.upvalues, f.nups*2+1 ); f.upvalues = realloc( f.upvalues, nups > 0 ? nups*2 : 1 );
f.upvalues[f.nups] = name; f.upvalues[nups] = new Upvaldesc(name, v.k == LexState.VLOCAL, v.u.info);
_assert (v.k == LexState.VLOCAL || v.k == LexState.VUPVAL); return nups++;
upvalues[f.nups] = new upvaldesc();
upvalues[f.nups].k = (short) (v.k);
upvalues[f.nups].info = (short) (v.u.s.info);
return f.nups++;
} }
int searchvar(LuaString n) { int searchvar(LuaString n) {
int i; int i;
for (i = nactvar - 1; i >= 0; i--) { for (i = nactvar - 1; i >= 0; i--) {
if (n == getlocvar(i).varname) if (n.eq_b(getlocvar(i).varname))
return i; return i;
} }
return -1; /* not found */ return -1; /* not found */
@@ -145,68 +160,89 @@ public class FuncState extends LuaC {
void markupval(int level) { void markupval(int level) {
BlockCnt bl = this.bl; BlockCnt bl = this.bl;
while (bl != null && bl.nactvar > level) while (bl.nactvar > level)
bl = bl.previous; bl = bl.previous;
if (bl != null)
bl.upval = true; bl.upval = true;
} }
int singlevaraux(LuaString n, expdesc var, int base) { static int singlevaraux(FuncState fs, LuaString n, expdesc var, int base) {
int v = searchvar(n); /* look up at current level */ if (fs == null) /* no more levels? */
return LexState.VVOID; /* default is global */
int v = fs.searchvar(n); /* look up at current level */
if (v >= 0) { if (v >= 0) {
var.init(LexState.VLOCAL, v); var.init(LexState.VLOCAL, v);
if (base == 0) if (base == 0)
markupval(v); /* local will be used as an upval */ fs.markupval(v); /* local will be used as an upval */
return LexState.VLOCAL; return LexState.VLOCAL;
} else { /* not found at current level; try upper one */ } else { /* not found at current level; try upvalues */
if (prev == null) { /* no more levels? */ int idx = fs.searchupvalue(n); /* try existing upvalues */
/* default is global variable */ if (idx < 0) { /* not found? */
var.init(LexState.VGLOBAL, NO_REG); if (singlevaraux(fs.prev, n, var, 0) == LexState.VVOID) /* try upper levels */
return LexState.VGLOBAL; return LexState.VVOID; /* not found; is a global */
/* else was LOCAL or UPVAL */
idx = fs.newupvalue(n, var); /* will be a new upvalue */
} }
if (prev.singlevaraux(n, var, 0) == LexState.VGLOBAL) var.init(LexState.VUPVAL, idx);
return LexState.VGLOBAL;
var.u.s.info = indexupvalue(n, var); /* else was LOCAL or UPVAL */
var.k = LexState.VUPVAL; /* upvalue in this level */
return LexState.VUPVAL; return LexState.VUPVAL;
} }
} }
void enterblock (BlockCnt bl, boolean isbreakable) { /*
bl.breaklist.i = LexState.NO_JUMP; ** "export" pending gotos to outer level, to check them against
bl.isbreakable = isbreakable; ** outer labels; if the block being exited has upvalues, and
bl.nactvar = this.nactvar; ** the goto exits the scope of any variable (which can be the
** upvalue), close those variables being exited.
*/
void movegotosout(BlockCnt bl) {
int i = bl.firstgoto;
final LexState.Labeldesc[] gl = ls.dyd.gt;
final int n_gt = ls.dyd.n_gt;
/* correct pending gotos to current block and try to close it
with visible labels */
while (i < n_gt) {
LexState.Labeldesc gt = gl[i];
if (gt.nactvar > bl.nactvar) {
if (bl.upval)
patchclose(gt.pc, bl.nactvar);
gt.nactvar = bl.nactvar;
}
if (!ls.findlabel(i))
i++; /* move to next one */
}
}
void enterblock (BlockCnt bl, boolean isloop) {
bl.isloop = isloop;
bl.nactvar = nactvar;
if (ls.dyd == null)
ls.dyd = new LexState.Dyndata();
bl.firstlabel = (short) ls.dyd.n_label;
bl.firstgoto = (short) ls.dyd.n_gt;
bl.upval = false; bl.upval = false;
bl.previous = this.bl; bl.previous = this.bl;
this.bl = bl; this.bl = bl;
_assert(this.freereg == this.nactvar); _assert(this.freereg == this.nactvar);
} }
//
// void leaveblock (FuncState *fs) {
// BlockCnt *bl = this.bl;
// this.bl = bl.previous;
// removevars(this.ls, bl.nactvar);
// if (bl.upval)
// this.codeABC(OP_CLOSE, bl.nactvar, 0, 0);
// /* a block either controls scope or breaks (never both) */
// assert(!bl.isbreakable || !bl.upval);
// assert(bl.nactvar == this.nactvar);
// this.freereg = this.nactvar; /* free registers */
// this.patchtohere(bl.breaklist);
// }
void leaveblock() { void leaveblock() {
BlockCnt bl = this.bl; BlockCnt bl = this.bl;
if (bl.previous != null && bl.upval) {
/* create a 'jump to here' to close upvalues */
int j = this.jump();
this.patchclose(j, bl.nactvar);
this.patchtohere(j);
}
if (bl.isloop)
ls.breaklabel(); /* close pending breaks */
this.bl = bl.previous; this.bl = bl.previous;
ls.removevars(bl.nactvar); this.removevars(bl.nactvar);
if (bl.upval) _assert(bl.nactvar == this.nactvar);
this.codeABC(OP_CLOSE, bl.nactvar, 0, 0);
/* a block either controls scope or breaks (never both) */
_assert (!bl.isbreakable || !bl.upval);
_assert (bl.nactvar == this.nactvar);
this.freereg = this.nactvar; /* free registers */ this.freereg = this.nactvar; /* free registers */
this.patchtohere(bl.breaklist.i); ls.dyd.n_label = bl.firstlabel; /* remove local labels */
if (bl.previous != null) /* inner block? */
this.movegotosout(bl); /* update pending gotos to outer block */
else if (bl.firstgoto < ls.dyd.n_gt) /* pending gotos in outer block? */
ls.undefgoto(ls.dyd.gt[bl.firstgoto]); /* error */
} }
void closelistfield(ConsControl cc) { void closelistfield(ConsControl cc) {
@@ -215,7 +251,7 @@ public class FuncState extends LuaC {
this.exp2nextreg(cc.v); this.exp2nextreg(cc.v);
cc.v.k = LexState.VVOID; cc.v.k = LexState.VVOID;
if (cc.tostore == LFIELDS_PER_FLUSH) { if (cc.tostore == LFIELDS_PER_FLUSH) {
this.setlist(cc.t.u.s.info, cc.na, cc.tostore); /* flush */ this.setlist(cc.t.u.info, cc.na, cc.tostore); /* flush */
cc.tostore = 0; /* no more items pending */ cc.tostore = 0; /* no more items pending */
} }
} }
@@ -228,13 +264,13 @@ public class FuncState extends LuaC {
if (cc.tostore == 0) return; if (cc.tostore == 0) return;
if (hasmultret(cc.v.k)) { if (hasmultret(cc.v.k)) {
this.setmultret(cc.v); this.setmultret(cc.v);
this.setlist(cc.t.u.s.info, cc.na, LUA_MULTRET); this.setlist(cc.t.u.info, cc.na, LUA_MULTRET);
cc.na--; /** do not count last expression (unknown number of elements) */ cc.na--; /** do not count last expression (unknown number of elements) */
} }
else { else {
if (cc.v.k != LexState.VVOID) if (cc.v.k != LexState.VVOID)
this.exp2nextreg(cc.v); this.exp2nextreg(cc.v);
this.setlist(cc.t.u.s.info, cc.na, cc.tostore); this.setlist(cc.t.u.info, cc.na, cc.tostore);
} }
} }
@@ -385,6 +421,17 @@ public class FuncState extends LuaC {
} }
} }
void patchclose(int list, int level) {
level++; /* argument is +1 to reserve 0 as non-op */
while (list != LexState.NO_JUMP) {
int next = getjump(list);
_assert(GET_OPCODE(f.code[list]) == OP_JMP
&& (GETARG_A(f.code[list]) == 0 || GETARG_A(f.code[list]) >= level));
SETARG_A(f.code, list, level);
list = next;
}
}
void patchtohere(int list) { void patchtohere(int list) {
this.getlabel(); this.getlabel();
this.concat(this.jpc, list); this.concat(this.jpc, list);
@@ -428,21 +475,23 @@ public class FuncState extends LuaC {
void freeexp(expdesc e) { void freeexp(expdesc e) {
if (e.k == LexState.VNONRELOC) if (e.k == LexState.VNONRELOC)
this.freereg(e.u.s.info); this.freereg(e.u.info);
} }
int addk(LuaValue v) { int addk(LuaValue v) {
int idx; if (this.h == null) {
if (this.htable.containsKey(v)) { this.h = new LuaTable();
idx = ((Integer) htable.get(v)).intValue();
} else { } else {
idx = this.nk; LuaValue idx = this.h.get(v);
this.htable.put(v, new Integer(idx)); if (idx.isnumber())
return idx.toint();
}
int idx = this.nk;
this.h.set(v, 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; f.k[this.nk++] = v;
}
return idx; return idx;
} }
@@ -481,7 +530,7 @@ public class FuncState extends LuaC {
void setoneret(expdesc e) { void setoneret(expdesc e) {
if (e.k == LexState.VCALL) { /* expression is an open function call? */ if (e.k == LexState.VCALL) { /* expression is an open function call? */
e.k = LexState.VNONRELOC; e.k = LexState.VNONRELOC;
e.u.s.info = GETARG_A(this.getcode(e)); e.u.info = GETARG_A(this.getcode(e));
} else if (e.k == LexState.VVARARG) { } else if (e.k == LexState.VVARARG) {
SETARG_B(this.getcodePtr(e), 2); SETARG_B(this.getcodePtr(e), 2);
e.k = LexState.VRELOCABLE; /* can relocate its simple result */ e.k = LexState.VRELOCABLE; /* can relocate its simple result */
@@ -495,20 +544,18 @@ public class FuncState extends LuaC {
break; break;
} }
case LexState.VUPVAL: { case LexState.VUPVAL: {
e.u.s.info = this.codeABC(OP_GETUPVAL, 0, e.u.s.info, 0); e.u.info = this.codeABC(OP_GETUPVAL, 0, e.u.info, 0);
e.k = LexState.VRELOCABLE;
break;
}
case LexState.VGLOBAL: {
e.u.s.info = this.codeABx(OP_GETGLOBAL, 0, e.u.s.info);
e.k = LexState.VRELOCABLE; e.k = LexState.VRELOCABLE;
break; break;
} }
case LexState.VINDEXED: { case LexState.VINDEXED: {
this.freereg(e.u.s.aux); int op = OP_GETTABUP; /* assume 't' is in an upvalue */
this.freereg(e.u.s.info); this.freereg(e.u.ind_idx);
e.u.s.info = this if (e.u.ind_vt == LexState.VLOCAL) { /* 't' is in a register? */
.codeABC(OP_GETTABLE, 0, e.u.s.info, e.u.s.aux); this.freereg(e.u.ind_t);
op = OP_GETTABLE;
}
e.u.info = this.codeABC(op, 0, e.u.ind_t, e.u.ind_idx);
e.k = LexState.VRELOCABLE; e.k = LexState.VRELOCABLE;
break; break;
} }
@@ -541,7 +588,7 @@ public class FuncState extends LuaC {
break; break;
} }
case LexState.VK: { case LexState.VK: {
this.codeABx(OP_LOADK, reg, e.u.s.info); this.codeABx(OP_LOADK, reg, e.u.info);
break; break;
} }
case LexState.VKNUM: { case LexState.VKNUM: {
@@ -554,8 +601,8 @@ public class FuncState extends LuaC {
break; break;
} }
case LexState.VNONRELOC: { case LexState.VNONRELOC: {
if (reg != e.u.s.info) if (reg != e.u.info)
this.codeABC(OP_MOVE, reg, e.u.s.info, 0); this.codeABC(OP_MOVE, reg, e.u.info, 0);
break; break;
} }
default: { default: {
@@ -563,7 +610,7 @@ public class FuncState extends LuaC {
return; /* nothing to do... */ return; /* nothing to do... */
} }
} }
e.u.s.info = reg; e.u.info = reg;
e.k = LexState.VNONRELOC; e.k = LexState.VNONRELOC;
} }
@@ -577,7 +624,7 @@ public class FuncState extends LuaC {
void exp2reg(expdesc e, int reg) { void exp2reg(expdesc e, int reg) {
this.discharge2reg(e, reg); this.discharge2reg(e, reg);
if (e.k == LexState.VJMP) if (e.k == LexState.VJMP)
this.concat(e.t, e.u.s.info); /* put this jump in `t' list */ this.concat(e.t, e.u.info); /* put this jump in `t' list */
if (e.hasjumps()) { if (e.hasjumps()) {
int _final; /* position after whole expression */ int _final; /* position after whole expression */
int p_f = LexState.NO_JUMP; /* position of an eventual LOAD false */ int p_f = LexState.NO_JUMP; /* position of an eventual LOAD false */
@@ -594,7 +641,7 @@ public class FuncState extends LuaC {
this.patchlistaux(e.t.i, _final, reg, p_t); this.patchlistaux(e.t.i, _final, reg, p_t);
} }
e.f.i = e.t.i = LexState.NO_JUMP; e.f.i = e.t.i = LexState.NO_JUMP;
e.u.s.info = reg; e.u.info = reg;
e.k = LexState.VNONRELOC; e.k = LexState.VNONRELOC;
} }
@@ -609,14 +656,14 @@ public class FuncState extends LuaC {
this.dischargevars(e); this.dischargevars(e);
if (e.k == LexState.VNONRELOC) { if (e.k == LexState.VNONRELOC) {
if (!e.hasjumps()) if (!e.hasjumps())
return e.u.s.info; /* exp is already in a register */ return e.u.info; /* exp is already in a register */
if (e.u.s.info >= this.nactvar) { /* reg. is not a local? */ if (e.u.info >= this.nactvar) { /* reg. is not a local? */
this.exp2reg(e, e.u.s.info); /* put value on it */ this.exp2reg(e, e.u.info); /* put value on it */
return e.u.s.info; return e.u.info;
} }
} }
this.exp2nextreg(e); /* default */ this.exp2nextreg(e); /* default */
return e.u.s.info; return e.u.info;
} }
void exp2val(expdesc e) { void exp2val(expdesc e) {
@@ -634,17 +681,17 @@ public class FuncState extends LuaC {
case LexState.VFALSE: case LexState.VFALSE:
case LexState.VNIL: { case LexState.VNIL: {
if (this.nk <= MAXINDEXRK) { /* constant fit in RK operand? */ if (this.nk <= MAXINDEXRK) { /* constant fit in RK operand? */
e.u.s.info = (e.k == LexState.VNIL) ? this.nilK() e.u.info = (e.k == LexState.VNIL) ? this.nilK()
: (e.k == LexState.VKNUM) ? this.numberK(e.u.nval()) : (e.k == LexState.VKNUM) ? this.numberK(e.u.nval())
: this.boolK((e.k == LexState.VTRUE)); : this.boolK((e.k == LexState.VTRUE));
e.k = LexState.VK; e.k = LexState.VK;
return RKASK(e.u.s.info); return RKASK(e.u.info);
} else } else
break; break;
} }
case LexState.VK: { case LexState.VK: {
if (e.u.s.info <= MAXINDEXRK) /* constant fit in argC? */ if (e.u.info <= MAXINDEXRK) /* constant fit in argC? */
return RKASK(e.u.s.info); return RKASK(e.u.info);
else else
break; break;
} }
@@ -659,22 +706,18 @@ public class FuncState extends LuaC {
switch (var.k) { switch (var.k) {
case LexState.VLOCAL: { case LexState.VLOCAL: {
this.freeexp(ex); this.freeexp(ex);
this.exp2reg(ex, var.u.s.info); this.exp2reg(ex, var.u.info);
return; return;
} }
case LexState.VUPVAL: { case LexState.VUPVAL: {
int e = this.exp2anyreg(ex); int e = this.exp2anyreg(ex);
this.codeABC(OP_SETUPVAL, e, var.u.s.info, 0); this.codeABC(OP_SETUPVAL, e, var.u.info, 0);
break;
}
case LexState.VGLOBAL: {
int e = this.exp2anyreg(ex);
this.codeABx(OP_SETGLOBAL, e, var.u.s.info);
break; break;
} }
case LexState.VINDEXED: { case LexState.VINDEXED: {
int op = (var.u.ind_vt == LexState.VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
int e = this.exp2RK(ex); int e = this.exp2RK(ex);
this.codeABC(OP_SETTABLE, var.u.s.info, var.u.s.aux, e); this.codeABC(op, var.u.ind_t, var.u.ind_idx, e);
break; break;
} }
default: { default: {
@@ -691,14 +734,14 @@ public class FuncState extends LuaC {
this.freeexp(e); this.freeexp(e);
func = this.freereg; func = this.freereg;
this.reserveregs(2); this.reserveregs(2);
this.codeABC(OP_SELF, func, e.u.s.info, this.exp2RK(key)); this.codeABC(OP_SELF, func, e.u.info, this.exp2RK(key));
this.freeexp(key); this.freeexp(key);
e.u.s.info = func; e.u.info = func;
e.k = LexState.VNONRELOC; e.k = LexState.VNONRELOC;
} }
void invertjump(expdesc e) { void invertjump(expdesc e) {
InstructionPtr pc = this.getjumpcontrol(e.u.s.info); InstructionPtr pc = this.getjumpcontrol(e.u.info);
_assert (testTMode(GET_OPCODE(pc.get())) _assert (testTMode(GET_OPCODE(pc.get()))
&& GET_OPCODE(pc.get()) != OP_TESTSET && Lua && GET_OPCODE(pc.get()) != OP_TESTSET && Lua
.GET_OPCODE(pc.get()) != OP_TEST); .GET_OPCODE(pc.get()) != OP_TEST);
@@ -719,7 +762,7 @@ public class FuncState extends LuaC {
} }
this.discharge2anyreg(e); this.discharge2anyreg(e);
this.freeexp(e); this.freeexp(e);
return this.condjump(OP_TESTSET, NO_REG, e.u.s.info, cond); return this.condjump(OP_TESTSET, NO_REG, e.u.info, cond);
} }
void goiftrue(expdesc e) { void goiftrue(expdesc e) {
@@ -738,7 +781,7 @@ public class FuncState extends LuaC {
} }
case LexState.VJMP: { case LexState.VJMP: {
this.invertjump(e); this.invertjump(e);
pc = e.u.s.info; pc = e.u.info;
break; break;
} }
default: { default: {
@@ -765,7 +808,7 @@ public class FuncState extends LuaC {
break; break;
} }
case LexState.VJMP: { case LexState.VJMP: {
pc = e.u.s.info; pc = e.u.info;
break; break;
} }
default: { default: {
@@ -800,7 +843,7 @@ public class FuncState extends LuaC {
case LexState.VNONRELOC: { case LexState.VNONRELOC: {
this.discharge2anyreg(e); this.discharge2anyreg(e);
this.freeexp(e); this.freeexp(e);
e.u.s.info = this.codeABC(OP_NOT, 0, e.u.s.info, 0); e.u.info = this.codeABC(OP_NOT, 0, e.u.info, 0);
e.k = LexState.VRELOCABLE; e.k = LexState.VRELOCABLE;
break; break;
} }
@@ -820,7 +863,9 @@ public class FuncState extends LuaC {
} }
void indexed(expdesc t, expdesc k) { void indexed(expdesc t, expdesc k) {
t.u.s.aux = this.exp2RK(k); t.u.ind_t = (short) t.u.info;
t.u.ind_idx = (short) this.exp2RK(k);
t.u.ind_vt = (short) ((t.k == LexState.VUPVAL) ? LexState.VUPVAL : LexState.VLOCAL);
t.k = LexState.VINDEXED; t.k = LexState.VINDEXED;
} }
@@ -881,7 +926,7 @@ public class FuncState extends LuaC {
this.freeexp(e2); this.freeexp(e2);
this.freeexp(e1); this.freeexp(e1);
} }
e1.u.s.info = this.codeABC(op, 0, o1, o2); e1.u.info = this.codeABC(op, 0, o1, o2);
e1.k = LexState.VRELOCABLE; e1.k = LexState.VRELOCABLE;
} }
} }
@@ -898,7 +943,7 @@ public class FuncState extends LuaC {
o2 = temp; /* o1 <==> o2 */ o2 = temp; /* o1 <==> o2 */
cond = 1; cond = 1;
} }
e1.u.s.info = this.condjump(op, cond, o1, o2); e1.u.info = this.condjump(op, cond, o1, o2);
e1.k = LexState.VJMP; e1.k = LexState.VJMP;
} }
@@ -979,11 +1024,11 @@ public class FuncState extends LuaC {
this.exp2val(e2); this.exp2val(e2);
if (e2.k == LexState.VRELOCABLE if (e2.k == LexState.VRELOCABLE
&& GET_OPCODE(this.getcode(e2)) == OP_CONCAT) { && GET_OPCODE(this.getcode(e2)) == OP_CONCAT) {
_assert (e1.u.s.info == GETARG_B(this.getcode(e2)) - 1); _assert (e1.u.info == GETARG_B(this.getcode(e2)) - 1);
this.freeexp(e1); this.freeexp(e1);
SETARG_B(this.getcodePtr(e2), e1.u.s.info); SETARG_B(this.getcodePtr(e2), e1.u.info);
e1.k = LexState.VRELOCABLE; e1.k = LexState.VRELOCABLE;
e1.u.s.info = e2.u.s.info; e1.u.info = e2.u.info;
} else { } else {
this.exp2nextreg(e2); /* operand must be on the 'stack' */ this.exp2nextreg(e2); /* operand must be on the 'stack' */
this.codearith(OP_CONCAT, e1, e2); this.codearith(OP_CONCAT, e1, e2);
@@ -1078,7 +1123,7 @@ public class FuncState extends LuaC {
this.codeABC(OP_SETLIST, base, b, 0); this.codeABC(OP_SETLIST, base, b, 0);
this.code(c, this.ls.lastline); this.code(c, this.ls.lastline);
} }
this.freereg = base + 1; /* free registers with list values */ this.freereg = (short) (base + 1); /* free registers with list values */
} }
} }

View File

@@ -105,13 +105,12 @@ public class LexState {
VKNUM = 5, /* nval = numerical value */ VKNUM = 5, /* nval = numerical value */
VLOCAL = 6, /* info = local register */ VLOCAL = 6, /* info = local register */
VUPVAL = 7, /* info = index of upvalue in `upvalues' */ VUPVAL = 7, /* info = index of upvalue in `upvalues' */
VGLOBAL = 8, /* info = index of table, aux = index of global name in `k' */ VINDEXED = 8, /* info = table register, aux = index register (or `k') */
VINDEXED = 9, /* info = table register, aux = index register (or `k') */ VJMP = 9, /* info = instruction pc */
VJMP = 10, /* info = instruction pc */ VRELOCABLE = 10, /* info = instruction pc */
VRELOCABLE = 11, /* info = instruction pc */ VNONRELOC = 11, /* info = result register */
VNONRELOC = 12, /* info = result register */ VCALL = 12, /* info = instruction pc */
VCALL = 13, /* info = instruction pc */ VVARARG = 13; /* info = instruction pc */
VVARARG = 14; /* info = instruction pc */
/* semantics information */ /* semantics information */
private static class SemInfo { private static class SemInfo {
@@ -139,7 +138,9 @@ public class LexState {
InputStream z; /* input stream */ InputStream z; /* input stream */
byte[] buff; /* buffer for tokens */ byte[] buff; /* buffer for tokens */
int nbuff; /* length of buffer */ int nbuff; /* length of buffer */
Dyndata dyd; /* dynamic structures used by the parser */
LuaString source; /* current source name */ LuaString source; /* current source name */
LuaString envn; /* environment variable name */
byte decpoint; /* locale decimal point */ byte decpoint; /* locale decimal point */
/* ORDER RESERVED */ /* ORDER RESERVED */
@@ -155,12 +156,12 @@ public class LexState {
final static int final static int
/* terminal symbols denoted by reserved words */ /* terminal symbols denoted by reserved words */
TK_AND=257, TK_BREAK=258, TK_DO=259, TK_ELSE=260, TK_ELSEIF=261, TK_AND=257, TK_BREAK=258, TK_DO=259, TK_ELSE=260, TK_ELSEIF=261,
TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_IF=266, TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_GOTO=266, TK_IF=267,
TK_IN=267, TK_LOCAL=268, TK_NIL=269, TK_NOT=270, TK_OR=271, TK_REPEAT=272, TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273,
TK_RETURN=273, TK_THEN=274, TK_TRUE=275, TK_UNTIL=276, TK_WHILE=277, TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278,
/* other terminal symbols */ /* other terminal symbols */
TK_CONCAT=278, TK_DOTS=279, TK_EQ=280, TK_GE=281, TK_LE=282, TK_NE=283, TK_CONCAT=279, TK_DOTS=280, TK_EQ=281, TK_GE=282, TK_LE=283, TK_NE=284,
TK_NUMBER=284, TK_NAME=285, TK_STRING=286, TK_EOS=287; TK_DBCOLON=285, TK_EOS=286, TK_NUMBER=287, TK_NAME=288, TK_STRING=289;
final static int FIRST_RESERVED = TK_AND; final static int FIRST_RESERVED = TK_AND;
final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED; final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED;
@@ -308,6 +309,7 @@ public class LexState {
this.linenumber = 1; this.linenumber = 1;
this.lastline = 1; this.lastline = 1;
this.source = source; this.source = source;
this.envn = LuaValue.ENV; /* environment variable name */
this.nbuff = 0; /* initialize buffer */ this.nbuff = 0; /* initialize buffer */
this.current = firstByte; /* read first char */ this.current = firstByte; /* read first char */
this.skipShebang(); this.skipShebang();
@@ -690,19 +692,27 @@ public class LexState {
// from lparser.c // from lparser.c
// ============================================================= // =============================================================
static final boolean vkisvar(final int k) {
return (VLOCAL <= (k) && (k) <= VINDEXED);
}
static final boolean vkisinreg(final int k) {
return ((k) == VNONRELOC || (k) == VLOCAL);
}
static class expdesc { static class expdesc {
int k; // expkind, from enumerated list, above int k; // expkind, from enumerated list, above
static class U { // originally a union static class U { // originally a union
static class S { short ind_idx; // index (R/K)
int info, aux; short ind_t; // table(register or upvalue)
} short ind_vt; // whether 't' is register (VLOCAL) or (UPVALUE)
final S s = new S();
private LuaValue _nval; private LuaValue _nval;
int info;
public void setNval(LuaValue r) { public void setNval(LuaValue r) {
_nval = r; _nval = r;
} }
public LuaValue nval() { public LuaValue nval() {
return (_nval == null? LuaInteger.valueOf(s.info): _nval); return (_nval == null? LuaInteger.valueOf(info): _nval);
} }
}; };
final U u = new U(); final U u = new U();
@@ -712,7 +722,7 @@ public class LexState {
this.f.i = NO_JUMP; this.f.i = NO_JUMP;
this.t.i = NO_JUMP; this.t.i = NO_JUMP;
this.k = k; this.k = k;
this.u.s.info = i; this.u.info = i;
} }
boolean hasjumps() { boolean hasjumps() {
@@ -725,14 +735,51 @@ public class LexState {
public void setvalue(expdesc other) { public void setvalue(expdesc other) {
this.k = other.k; this.k = other.k;
this.u._nval = other.u._nval; this.u.info = other.u.info;
this.u.s.info = other.u.s.info; this.u.ind_idx = other.u.ind_idx;
this.u.s.aux = other.u.s.aux; this.u.ind_t = other.u.ind_t;
this.u.ind_vt = other.u.ind_vt;
this.t.i = other.t.i; this.t.i = other.t.i;
this.f.i = other.f.i; this.f.i = other.f.i;
} }
} }
/* description of active local variable */
static class Vardesc {
final short idx; /* variable index in stack */
Vardesc(int idx) {
this.idx = (short) idx;
}
};
/* description of pending goto statements and label statements */
static class Labeldesc {
LuaString name; /* label identifier */
int pc; /* position in code */
int line; /* line where it appeared */
short nactvar; /* local level where it appears in current block */
public Labeldesc(LuaString name, int pc, int line, short nactvar) {
this.name = name;
this.pc = pc;
this.line = line;
this.nactvar = nactvar;
}
};
/* dynamic structures used by the parser */
static class Dyndata {
Vardesc[] actvar; /* list of active local variables */
int n_actvar = 0;
Labeldesc[] gt; /* list of pending gotos */
int n_gt = 0;
Labeldesc[] label; /* list of active labels */
int n_label = 0;
};
boolean hasmultret(int k) { boolean hasmultret(int k) {
return ((k) == VCALL || (k) == VVARARG); return ((k) == VCALL || (k) == VVARARG);
} }
@@ -741,9 +788,21 @@ public class LexState {
name args description name args description
------------------------------------------------------------------------*/ ------------------------------------------------------------------------*/
/* void anchor_token () {
* * prototypes for recursive non-terminal functions /* last token from outer function must be EOS */
*/ LuaC._assert(fs != null || t.token == TK_EOS);
if (t.token == TK_NAME || t.token == TK_STRING) {
LuaString ts = t.seminfo.ts;
// TODO: is this necessary?
newstring(ts.m_bytes, 0, ts.m_length);
}
}
/* semantic error */
void semerror (String msg) {
t.token = 0; /* remove 'near to' from final message */
syntaxerror(msg);
}
void error_expected(int token) { void error_expected(int token) {
syntaxerror(L.pushfstring(LUA_QS(token2str(token)) + " expected")); syntaxerror(L.pushfstring(LUA_QS(token2str(token)) + " expected"));
@@ -822,9 +881,11 @@ public class LexState {
} }
void new_localvar(LuaString name, int n) { void new_localvar(LuaString name, int n) {
FuncState fs = this.fs; int reg = registerlocalvar(name);
fs.checklimit(fs.nactvar + n + 1, FuncState.LUAI_MAXVARS, "local variables"); fs.checklimit(fs.nactvar + n + 1, FuncState.LUAI_MAXVARS, "local variables");
fs.actvar[fs.nactvar + n] = (short) registerlocalvar(name); if (dyd.actvar == null || dyd.n_actvar + 1 > dyd.actvar.length)
dyd.actvar = LuaC.realloc(dyd.actvar, Math.max(1, dyd.n_actvar * 2));
dyd.actvar[dyd.n_actvar] = new Vardesc(reg);
} }
void adjustlocalvars(int nvars) { void adjustlocalvars(int nvars) {
@@ -844,8 +905,13 @@ public class LexState {
void singlevar(expdesc var) { void singlevar(expdesc var) {
LuaString varname = this.str_checkname(); LuaString varname = this.str_checkname();
FuncState fs = this.fs; FuncState fs = this.fs;
if (fs.singlevaraux(varname, var, 1) == VGLOBAL) if (FuncState.singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
var.u.s.info = fs.stringK(varname); /* info points to global name */ expdesc key = new expdesc();
FuncState.singlevaraux(fs, this.envn, var, 1); /* get environment variable */
LuaC._assert(var.k == VLOCAL || var.k == VUPVAL);
this.codestring(key, varname); /* key is variable name */
fs.indexed(var, key); /* env[varname] */
}
} }
void adjust_assign(int nvars, int nexps, expdesc e) { void adjust_assign(int nvars, int nexps, expdesc e) {
@@ -881,21 +947,90 @@ public class LexState {
L.nCcalls--; L.nCcalls--;
} }
void pushclosure(FuncState func, expdesc v) { void closegoto(int g, Labeldesc label) {
int i;
FuncState fs = this.fs; FuncState fs = this.fs;
Prototype f = fs.f; Labeldesc[] gl = this.dyd.gt;
if (f.p == null || fs.np + 1 > f.p.length) Labeldesc gt = gl[g];
f.p = LuaC.realloc( f.p, fs.np*2 + 1 ); LuaC._assert(gt.name.eq_b(label.name));
f.p[fs.np++] = func.f; if (gt.nactvar < label.nactvar) {
v.init(VRELOCABLE, fs.codeABx(Lua.OP_CLOSURE, 0, fs.np - 1)); LuaString vname = fs.getlocvar(gt.nactvar).varname;
for (int i = 0; i < func.f.nups; i++) { String msg = L.pushfstring("<goto " + gt.name + "> at line "
int o = (func.upvalues[i].k == VLOCAL) ? Lua.OP_MOVE + gt.line + " jumps into the scope of local '"
: Lua.OP_GETUPVAL; + vname.tojstring() + "'");
fs.codeABC(o, 0, func.upvalues[i].info, 0); semerror(msg);
}
fs.patchlist(gt.pc, label.pc);
/* remove goto from pending list */
System.arraycopy(gl, g + 1, gl, g, this.dyd.n_gt - g - 1);
gl[--this.dyd.n_gt] = null;
}
/*
** try to close a goto with existing labels; this solves backward jumps
*/
boolean findlabel (int g) {
int i;
BlockCnt bl = fs.bl;
Dyndata dyd = this.dyd;
Labeldesc gt = dyd.gt[g];
/* check labels in current block for a match */
for (i = bl.firstlabel; i < dyd.n_label; i++) {
Labeldesc lb = dyd.label[i];
if (lb.name.eq_b(gt.name)) { /* correct label? */
if (gt.nactvar > lb.nactvar &&
(bl.upval || dyd.n_label > bl.firstlabel))
fs.patchclose(gt.pc, lb.nactvar);
closegoto(g, lb); /* close it */
return true;
}
}
return false; /* label not found; cannot close goto */
}
/* Caller must LuaC.grow() the vector before calling this. */
int newlabelentry(Labeldesc[] l, int index, LuaString name, int line, int pc) {
l[index] = new Labeldesc(name, pc, line, fs.nactvar);
return index;
}
/*
** check whether new label 'lb' matches any pending gotos in current
** block; solves forward jumps
*/
void findgotos (Labeldesc lb) {
Labeldesc[] gl = dyd.gt;
int i = fs.bl.firstgoto;
while (i < dyd.n_gt) {
if (gl[i].name.eq_b(lb.name))
closegoto(i, lb);
else
i++;
} }
} }
void open_func (FuncState fs) {
/*
** create a label named "break" to resolve break statements
*/
void breaklabel () {
LuaString n = LuaString.valueOf("break");
int l = newlabelentry(LuaC.grow(dyd.label, dyd.n_label+1), dyd.n_label++, n, 0, fs.pc);
findgotos(dyd.label[l]);
}
/*
** generates an error for an undefined 'goto'; choose appropriate
** message when label name is a reserved word (which can only be 'break')
*/
void undefgoto (Labeldesc gt) {
String msg = L.pushfstring(isReservedKeyword(gt.name.tojstring())
? "<"+gt.name+"> at line "+gt.line+" not inside a loop"
: "no visible label '"+gt.name+"' for <goto> at line "+gt.line);
semerror(msg);
}
void open_func (FuncState fs, BlockCnt bl) {
LuaC L = this.L; LuaC L = this.L;
Prototype f = new Prototype(); Prototype f = new Prototype();
if ( this.fs!=null ) if ( this.fs!=null )
@@ -915,14 +1050,14 @@ public class LexState {
fs.nactvar = 0; fs.nactvar = 0;
fs.bl = null; fs.bl = null;
f.maxstacksize = 2; /* registers 0/1 are always valid */ f.maxstacksize = 2; /* registers 0/1 are always valid */
//fs.h = new LTable(); fs.enterblock(bl, false);
fs.htable = new Hashtable();
} }
void close_func() { void close_func() {
FuncState fs = this.fs; FuncState fs = this.fs;
Prototype f = fs.f; Prototype f = fs.f;
this.removevars(0); fs.ret(0, 0);
fs.leaveblock();
fs.ret(0, 0); /* final return */ fs.ret(0, 0); /* final return */
f.code = LuaC.realloc(f.code, fs.pc); f.code = LuaC.realloc(f.code, fs.pc);
f.lineinfo = LuaC.realloc(f.lineinfo, fs.pc); f.lineinfo = LuaC.realloc(f.lineinfo, fs.pc);
@@ -931,7 +1066,7 @@ public class LexState {
f.p = LuaC.realloc(f.p, fs.np); f.p = LuaC.realloc(f.p, fs.np);
f.locvars = LuaC.realloc(f.locvars, fs.nlocvars); f.locvars = LuaC.realloc(f.locvars, fs.nlocvars);
// f.sizelocvars = fs.nlocvars; // f.sizelocvars = fs.nlocvars;
f.upvalues = LuaC.realloc(f.upvalues, f.nups); f.upvalues = LuaC.realloc(f.upvalues, fs.nups);
// LuaC._assert (CheckCode.checkcode(f)); // LuaC._assert (CheckCode.checkcode(f));
LuaC._assert (fs.bl == null); LuaC._assert (fs.bl == null);
this.fs = fs.prev; this.fs = fs.prev;
@@ -997,8 +1132,8 @@ public class LexState {
this.checknext('='); this.checknext('=');
rkkey = fs.exp2RK(key); rkkey = fs.exp2RK(key);
this.expr(val); this.expr(val);
fs.codeABC(Lua.OP_SETTABLE, cc.t.u.s.info, rkkey, fs.exp2RK(val)); fs.codeABC(Lua.OP_SETTABLE, cc.t.u.info, rkkey, fs.exp2RK(val));
fs.freereg = reg; /* free registers */ fs.freereg = (short)reg; /* free registers */
} }
void listfield (ConsControl cc) { void listfield (ConsControl cc) {
@@ -1106,7 +1241,8 @@ public class LexState {
void body(expdesc e, boolean needself, int line) { void body(expdesc e, boolean needself, int line) {
/* body -> `(' parlist `)' chunk END */ /* body -> `(' parlist `)' chunk END */
FuncState new_fs = new FuncState(); FuncState new_fs = new FuncState();
open_func(new_fs); BlockCnt bl = new BlockCnt();
open_func(new_fs, bl);
new_fs.f.linedefined = line; new_fs.f.linedefined = line;
this.checknext('('); this.checknext('(');
if (needself) { if (needself) {
@@ -1115,11 +1251,10 @@ public class LexState {
} }
this.parlist(); this.parlist();
this.checknext(')'); this.checknext(')');
this.chunk(); this.statlist();
new_fs.f.lastlinedefined = this.linenumber; new_fs.f.lastlinedefined = this.linenumber;
this.check_match(TK_END, TK_FUNCTION, line); this.check_match(TK_END, TK_FUNCTION, line);
this.close_func(); this.close_func();
this.pushclosure(new_fs, e);
} }
int explist1(expdesc v) { int explist1(expdesc v) {
@@ -1169,7 +1304,7 @@ public class LexState {
} }
} }
LuaC._assert (f.k == VNONRELOC); LuaC._assert (f.k == VNONRELOC);
base = f.u.s.info; /* base register for call */ base = f.u.info; /* base register for call */
if (hasmultret(args.k)) if (hasmultret(args.k))
nparams = Lua.LUA_MULTRET; /* open call */ nparams = Lua.LUA_MULTRET; /* open call */
else { else {
@@ -1179,7 +1314,7 @@ public class LexState {
} }
f.init(VCALL, fs.codeABC(Lua.OP_CALL, base, nparams + 1, 2)); f.init(VCALL, fs.codeABC(Lua.OP_CALL, base, nparams + 1, 2));
fs.fixline(line); fs.fixline(line);
fs.freereg = base+1; /* call remove function and arguments and leaves fs.freereg = (short)(base+1); /* call remove function and arguments and leaves
* (unless changed) one result */ * (unless changed) one result */
} }
@@ -1427,11 +1562,12 @@ public class LexState {
*/ */
boolean block_follow (int token) { boolean block_follow (boolean withuntil) {
switch (token) { switch (t.token) {
case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOS:
case TK_UNTIL: case TK_EOS:
return true; return true;
case TK_UNTIL:
return withuntil;
default: return false; default: return false;
} }
} }
@@ -1442,8 +1578,7 @@ public class LexState {
FuncState fs = this.fs; FuncState fs = this.fs;
BlockCnt bl = new BlockCnt(); BlockCnt bl = new BlockCnt();
fs.enterblock(bl, false); fs.enterblock(bl, false);
this.chunk(); this.statlist();
LuaC._assert(bl.breaklist.i == NO_JUMP);
fs.leaveblock(); fs.leaveblock();
} }
@@ -1467,22 +1602,25 @@ public class LexState {
*/ */
void check_conflict (LHS_assign lh, expdesc v) { void check_conflict (LHS_assign lh, expdesc v) {
FuncState fs = this.fs; FuncState fs = this.fs;
int extra = fs.freereg; /* eventual position to save local variable */ short extra = (short) fs.freereg; /* eventual position to save local variable */
boolean conflict = false; boolean conflict = false;
for (; lh!=null; lh = lh.prev) { for (; lh!=null; lh = lh.prev) {
if (lh.v.k == VINDEXED) { if (lh.v.k == VINDEXED) {
if (lh.v.u.s.info == v.u.s.info) { /* conflict? */ /* table is the upvalue/local being assigned now? */
if (lh.v.u.ind_vt == v.k && lh.v.u.ind_t == v.u.info) {
conflict = true; conflict = true;
lh.v.u.s.info = extra; /* previous assignment will use safe copy */ lh.v.u.ind_vt = VLOCAL;
lh.v.u.ind_t = extra; /* previous assignment will use safe copy */
} }
if (lh.v.u.s.aux == v.u.s.info) { /* conflict? */ /* index is the local being assigned? (index cannot be upvalue) */
if (v.k == VLOCAL && lh.v.u.ind_idx == v.u.info) {
conflict = true; conflict = true;
lh.v.u.s.aux = extra; /* previous assignment will use safe copy */ lh.v.u.ind_idx = extra; /* previous assignment will use safe copy */
} }
} }
} }
if (conflict) { if (conflict) {
fs.codeABC(Lua.OP_MOVE, fs.freereg, v.u.s.info, 0); /* make copy */ fs.codeABC(Lua.OP_MOVE, fs.freereg, v.u.info, 0); /* make copy */
fs.reserveregs(1); fs.reserveregs(1);
} }
} }
@@ -1532,21 +1670,44 @@ public class LexState {
return v.f.i; return v.f.i;
} }
void gotostat(int pc) {
int line = linenumber;
LuaString label;
int g;
if (testnext(TK_GOTO))
label = str_checkname();
else {
next(); /* skip break */
label = LuaString.valueOf("break");
}
g = newlabelentry(LuaC.grow(dyd.gt, dyd.n_gt+1), dyd.n_gt++, label, line, pc);
findlabel(g); /* close it if label already defined */
}
void breakstat() {
/* skip no-op statements */
void skipnoopstat () {
while (t.token == ';' || t.token == TK_DBCOLON)
statement();
}
void labelstat (LuaString label, int line) {
/* label -> '::' NAME '::' */
FuncState fs = this.fs; FuncState fs = this.fs;
BlockCnt bl = fs.bl; Labeldesc[] ll = dyd.label;
boolean upval = false; int l; /* index of new label being created */
while (bl != null && !bl.isbreakable) { fs.checkrepeated(ll, dyd.n_label, label); /* check for repeated labels */
upval |= bl.upval; checknext(TK_DBCOLON); /* skip double colon */
bl = bl.previous; /* create new entry for this label */
} l = newlabelentry(LuaC.grow(ll, dyd.n_label+1), dyd.n_label++, label, line, fs.pc);
if (bl == null) skipnoopstat(); /* skip other no-op statements */
this.syntaxerror("no loop to break"); if (block_follow(false)) { /* label is last no-op statement in the block? */
if (upval) /* assume that locals are already out of scope */
fs.codeABC(Lua.OP_CLOSE, bl.nactvar, 0, 0); ll[l].nactvar = fs.bl.nactvar;
fs.concat(bl.breaklist, fs.jump());
} }
findgotos(ll[l]);
}
void whilestat (int line) { void whilestat (int line) {
@@ -1577,18 +1738,14 @@ public class LexState {
fs.enterblock(bl1, true); /* loop block */ fs.enterblock(bl1, true); /* loop block */
fs.enterblock(bl2, false); /* scope block */ fs.enterblock(bl2, false); /* scope block */
this.next(); /* skip REPEAT */ this.next(); /* skip REPEAT */
this.chunk(); this.statlist();
this.check_match(TK_UNTIL, TK_REPEAT, line); this.check_match(TK_UNTIL, TK_REPEAT, line);
condexit = this.cond(); /* read condition (inside scope block) */ condexit = this.cond(); /* read condition (inside scope block) */
if (!bl2.upval) { /* no upvalues? */ if (bl2.upval) { /* upvalues? */
fs.patchclose(condexit, bl2.nactvar);
}
fs.leaveblock(); /* finish scope */ fs.leaveblock(); /* finish scope */
fs.patchlist(condexit, repeat_init); /* close the loop */ fs.patchlist(condexit, repeat_init); /* close the loop */
} else { /* complete semantics when there are upvalues */
this.breakstat(); /* if condition then break */
fs.patchtohere(condexit); /* else... */
fs.leaveblock(); /* finish scope... */
fs.patchlist(fs.jump(), repeat_init); /* and repeat */
}
fs.leaveblock(); /* finish loop */ fs.leaveblock(); /* finish loop */
} }
@@ -1807,7 +1964,7 @@ public class LexState {
expdesc e = new expdesc(); expdesc e = new expdesc();
int first, nret; /* registers with returned values */ int first, nret; /* registers with returned values */
this.next(); /* skip RETURN */ this.next(); /* skip RETURN */
if (block_follow(this.t.token) || this.t.token == ';') if (block_follow(true) || this.t.token == ';')
first = nret = 0; /* return no values */ first = nret = 0; /* return no values */
else { else {
nret = this.explist1(e); /* optional return values */ nret = this.explist1(e); /* optional return values */
@@ -1874,9 +2031,10 @@ public class LexState {
this.retstat(); this.retstat();
return true; /* must be last statement */ return true; /* must be last statement */
} }
case TK_BREAK: { /* stat -> breakstat */ case TK_BREAK:
case TK_GOTO: { /* stat -> breakstat */
this.next(); /* skip BREAK */ this.next(); /* skip BREAK */
this.breakstat(); this.gotostat(fs.jump());
return true; /* must be last statement */ return true; /* must be last statement */
} }
default: { default: {
@@ -1886,18 +2044,32 @@ public class LexState {
} }
} }
void chunk() { void statlist() {
/* chunk -> { stat [`;'] } */ /* statlist -> { stat [`;'] } */
boolean islast = false; while (!block_follow(true)) {
this.enterlevel(); if (t.token == TK_RETURN) {
while (!islast && !block_follow(this.t.token)) { statement();
islast = this.statement(); return; /* 'return' must be last statement */
this.testnext(';');
LuaC._assert (this.fs.f.maxstacksize >= this.fs.freereg
&& this.fs.freereg >= this.fs.nactvar);
this.fs.freereg = this.fs.nactvar; /* free registers */
} }
this.leavelevel(); statement();
}
}
/*
** compiles the main function, which is a regular vararg function with an
** upvalue named LUA_ENV
*/
public void mainfunc(FuncState funcstate) {
BlockCnt bl = new BlockCnt();
open_func(funcstate, bl);
fs.f.is_vararg = 1; /* main function is always vararg */
expdesc v = new expdesc();
v.init(VLOCAL, 0); /* create and... */
fs.newupvalue(envn, v); /* ...set environment upvalue */
next(); /* read first token */
statlist(); /* parse main body */
check(TK_EOS);
close_func();
} }
/* }====================================================================== */ /* }====================================================================== */

View File

@@ -34,6 +34,7 @@ import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype; import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
import org.luaj.vm2.LoadState.LuaCompiler; import org.luaj.vm2.LoadState.LuaCompiler;
/** /**
@@ -83,7 +84,7 @@ public class LuaC extends Lua implements LuaCompiler {
} }
public static final int MAXSTACK = 250; public static final int MAXSTACK = 250;
static final int LUAI_MAXUPVALUES = 60; static final int LUAI_MAXUPVAL = 0xff;
static final int LUAI_MAXVARS = 200; static final int LUAI_MAXVARS = 200;
static final int NO_REG = MAXARG_A; static final int NO_REG = MAXARG_A;
@@ -106,6 +107,10 @@ public class LuaC extends Lua implements LuaCompiler {
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) ); i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
} }
static void SETARG_A(int[] code, int index, int u) {
code[index] = (code[index] & (MASK_NOT_A)) | ((u << POS_A) & MASK_A);
}
static void SETARG_A(InstructionPtr i,int u) { static void SETARG_A(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) ); i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) );
} }
@@ -169,6 +174,31 @@ public class LuaC extends Lua implements LuaCompiler {
return a; return a;
} }
static Upvaldesc[] realloc(Upvaldesc[] v, int n) {
Upvaldesc[] a = new Upvaldesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LexState.Vardesc[] realloc(LexState.Vardesc[] v, int n) {
LexState.Vardesc[] a = new LexState.Vardesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LexState.Labeldesc[] grow(LexState.Labeldesc[] v, int min_n) {
return v == null ? new LexState.Labeldesc[2] : v.length <= min_n ? v : realloc(v, v.length*2);
}
static LexState.Labeldesc[] realloc(LexState.Labeldesc[] v, int n) {
LexState.Labeldesc[] a = new LexState.Labeldesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static int[] realloc(int[] v, int n) { static int[] realloc(int[] v, int n) {
int[] a = new int[n]; int[] a = new int[n];
if ( v != null ) if ( v != null )
@@ -206,23 +236,22 @@ public class LuaC extends Lua implements LuaCompiler {
(new LuaC(new Hashtable())).luaY_parser(firstByte, stream, name); (new LuaC(new Hashtable())).luaY_parser(firstByte, stream, name);
} }
/** Parse the input */ /** Parse the input */
private Prototype luaY_parser(int firstByte, InputStream z, String name) { private Prototype luaY_parser(int firstByte, InputStream z, String name) {
LexState lexstate = new LexState(this, z); LexState lexstate = new LexState(this, z);
FuncState funcstate = new FuncState(); FuncState funcstate = new FuncState();
// lexstate.buff = buff; // lexstate.buff = buff;
lexstate.fs = funcstate;
lexstate.setinput( this, firstByte, z, (LuaString) LuaValue.valueOf(name) ); lexstate.setinput( this, firstByte, z, (LuaString) LuaValue.valueOf(name) );
lexstate.open_func(funcstate);
/* main func. is always vararg */ /* main func. is always vararg */
funcstate.f.is_vararg = LuaC.VARARG_ISVARARG; funcstate.f = new Prototype();
funcstate.f.source = (LuaString) LuaValue.valueOf(name); funcstate.f.source = (LuaString) LuaValue.valueOf(name);
lexstate.next(); /* read first token */ lexstate.mainfunc(funcstate);
lexstate.chunk();
lexstate.check(LexState.TK_EOS);
lexstate.close_func();
LuaC._assert (funcstate.prev == null); LuaC._assert (funcstate.prev == null);
LuaC._assert (funcstate.f.nups == 0); /* all scopes should be correctly finished */
LuaC._assert (lexstate.fs == null); LuaC._assert (lexstate.dyd == null
|| (lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0));
return funcstate.f; return funcstate.f;
} }

View File

@@ -123,6 +123,7 @@ public class DebugLib extends VarArgFunction {
private static final LuaString COUNT = valueOf("count"); private static final LuaString COUNT = valueOf("count");
private static final LuaString RETURN = valueOf("return"); private static final LuaString RETURN = valueOf("return");
private static final LuaString TAILRETURN = valueOf("tail return"); private static final LuaString TAILRETURN = valueOf("tail return");
private static final LuaString CONSTANT = valueOf("constant");
private static final LuaString FUNC = valueOf("func"); private static final LuaString FUNC = valueOf("func");
private static final LuaString NUPS = valueOf("nups"); private static final LuaString NUPS = valueOf("nups");
@@ -219,7 +220,7 @@ public class DebugLib extends VarArgFunction {
public LuaString[] getfunckind() { public LuaString[] getfunckind() {
if ( closure == null || pc<0 ) return null; if ( closure == null || pc<0 ) return null;
int stackpos = (closure.p.code[pc] >> 6) & 0xff; int stackpos = (closure.p.code[pc] >> 6) & 0xff;
return getobjname(this, stackpos); return getobjname(this, pc, stackpos);
} }
public String sourceline() { public String sourceline() {
if ( closure == null ) return func.tojstring(); if ( closure == null ) return func.tojstring();
@@ -500,7 +501,7 @@ public class DebugLib extends VarArgFunction {
break; break;
} }
case 'u': { case 'u': {
info.set(NUPS, valueOf(c!=null? c.p.nups: 0)); info.set(NUPS, valueOf(c!=null? c.p.upvalues.length: 0));
break; break;
} }
case 'n': { case 'n': {
@@ -604,7 +605,7 @@ public class DebugLib extends VarArgFunction {
static LuaString findupvalue(LuaClosure c, int up) { static LuaString findupvalue(LuaClosure c, int up) {
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) { if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
if ( c.p.upvalues != null && up <= c.p.upvalues.length ) if ( c.p.upvalues != null && up <= c.p.upvalues.length )
return c.p.upvalues[up-1]; return c.p.upvalues[up-1].name;
else else
return LuaString.valueOf( "."+up ); return LuaString.valueOf( "."+up );
} }
@@ -720,40 +721,53 @@ public class DebugLib extends VarArgFunction {
// return StrValue[] { name, namewhat } if found, null if not // return StrValue[] { name, namewhat } if found, null if not
static LuaString[] getobjname(DebugInfo di, int stackpos) { static LuaString[] getobjname(DebugInfo di, int lastpc, int reg) {
LuaString name; if (di.closure == null)
if (di.closure != null) { /* a Lua function? */ return null; /* Not a Lua function? */
Prototype p = di.closure.p; Prototype p = di.closure.p;
int pc = di.pc; // currentpc(L, ci); int pc = di.pc; // currentpc(L, ci);
int i;// Instruction i; LuaString name = p.getlocalname(reg + 1, pc);
name = p.getlocalname(stackpos + 1, pc);
if (name != null) /* is a local? */ if (name != null) /* is a local? */
return new LuaString[] { name, LOCAL }; return new LuaString[] { name, LOCAL };
i = symbexec(p, pc, stackpos); /* try symbolic execution */
lua_assert(pc != -1); /* else try symbolic execution */
pc = findsetreg(p, lastpc, reg);
if (pc != -1) { /* could find instruction? */
int i = p.code[pc];
switch (Lua.GET_OPCODE(i)) { switch (Lua.GET_OPCODE(i)) {
case Lua.OP_GETGLOBAL: {
int g = Lua.GETARG_Bx(i); /* global index */
// lua_assert(p.k[g].isString());
return new LuaString[] { p.k[g].strvalue(), GLOBAL };
}
case Lua.OP_MOVE: { case Lua.OP_MOVE: {
int a = Lua.GETARG_A(i); int a = Lua.GETARG_A(i);
int b = Lua.GETARG_B(i); /* move from `b' to `a' */ int b = Lua.GETARG_B(i); /* move from `b' to `a' */
if (b < a) if (b < a)
return getobjname(di, b); /* get name for `b' */ return getobjname(di, pc, b); /* get name for `b' */
break; break;
} }
case Lua.OP_GETTABUP:
case Lua.OP_GETTABLE: { case Lua.OP_GETTABLE: {
int k = Lua.GETARG_C(i); /* key index */ int k = Lua.GETARG_C(i); /* key index */
int t = Lua.GETARG_Bx(i); /* table index */
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */
? p.getlocalname(t + 1, pc)
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
name = kname(p, k); name = kname(p, k);
return new LuaString[] { name, FIELD }; return new LuaString[] { name, vn.eq_b(ENV)? GLOBAL: FIELD };
} }
case Lua.OP_GETUPVAL: { case Lua.OP_GETUPVAL: {
int u = Lua.GETARG_B(i); /* upvalue index */ int u = Lua.GETARG_B(i); /* upvalue index */
name = u < p.upvalues.length ? p.upvalues[u] : QMARK; name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
return new LuaString[] { name, UPVALUE }; return new LuaString[] { name, UPVALUE };
} }
case Lua.OP_LOADK:
case Lua.OP_LOADKX: {
int b = (Lua.GET_OPCODE(i) == Lua.OP_LOADK) ? Lua.GETARG_Bx(i)
: Lua.GETARG_Ax(p.code[pc + 1]);
if (p.k[b].isstring()) {
name = p.k[b].strvalue();
return new LuaString[] { name, CONSTANT };
}
break;
}
case Lua.OP_SELF: { case Lua.OP_SELF: {
int k = Lua.GETARG_C(i); /* key index */ int k = Lua.GETARG_C(i); /* key index */
name = kname(p, k); name = kname(p, k);
@@ -782,7 +796,7 @@ public class DebugLib extends VarArgFunction {
lua_assert(pt.numparams + (pt.is_vararg & Lua.VARARG_HASARG) <= pt.maxstacksize); lua_assert(pt.numparams + (pt.is_vararg & Lua.VARARG_HASARG) <= pt.maxstacksize);
lua_assert((pt.is_vararg & Lua.VARARG_NEEDSARG) == 0 lua_assert((pt.is_vararg & Lua.VARARG_NEEDSARG) == 0
|| (pt.is_vararg & Lua.VARARG_HASARG) != 0); || (pt.is_vararg & Lua.VARARG_HASARG) != 0);
if (!(pt.upvalues.length <= pt.nups)) return false; // if (!(pt.upvalues.length <= pt.nups)) return false;
if (!(pt.lineinfo.length == pt.code.length || pt.lineinfo.length == 0)) return false; if (!(pt.lineinfo.length == pt.code.length || pt.lineinfo.length == 0)) return false;
if (!(Lua.GET_OPCODE(pt.code[pt.code.length - 1]) == Lua.OP_RETURN)) return false; if (!(Lua.GET_OPCODE(pt.code[pt.code.length - 1]) == Lua.OP_RETURN)) return false;
return true; return true;
@@ -816,162 +830,51 @@ public class DebugLib extends VarArgFunction {
return true; return true;
} }
/*
// return last instruction, or 0 if error ** try to find last instruction before 'lastpc' that modified register 'reg'
static int symbexec(Prototype pt, int lastpc, int reg) {
int pc;
int last; /* stores position of last instruction that changed `reg' */
last = pt.code.length - 1; /*
* points to final return (a `neutral'
* instruction)
*/ */
if (!(precheck(pt))) return 0; static int findsetreg (Prototype p, int lastpc, int reg) {
int pc;
int setreg = -1; /* keep last instruction that changed 'reg' */
for (pc = 0; pc < lastpc; pc++) { for (pc = 0; pc < lastpc; pc++) {
int i = pt.code[pc]; int i = p.code[pc];
int op = Lua.GET_OPCODE(i); int op = Lua.GET_OPCODE(i);
int a = Lua.GETARG_A(i); int a = Lua.GETARG_A(i);
int b = 0;
int c = 0;
if (!(op < Lua.NUM_OPCODES)) return 0;
if (!checkreg(pt, a)) return 0;
switch (Lua.getOpMode(op)) {
case Lua.iABC: {
b = Lua.GETARG_B(i);
c = Lua.GETARG_C(i);
if (!(checkArgMode(pt, b, Lua.getBMode(op)))) return 0;
if (!(checkArgMode(pt, c, Lua.getCMode(op)))) return 0;
break;
}
case Lua.iABx: {
b = Lua.GETARG_Bx(i);
if (Lua.getBMode(op) == Lua.OpArgK)
if (!(b < pt.k.length)) return 0;
break;
}
case Lua.iAsBx: {
b = Lua.GETARG_sBx(i);
if (Lua.getBMode(op) == Lua.OpArgR) {
int dest = pc + 1 + b;
if (!(0 <= dest && dest < pt.code.length)) return 0;
if (dest > 0) {
/* cannot jump to a setlist count */
int d = pt.code[dest - 1];
if ((Lua.GET_OPCODE(d) == Lua.OP_SETLIST && Lua.GETARG_C(d) == 0)) return 0;
}
}
break;
}
}
if (Lua.testAMode(op)) {
if (a == reg)
last = pc; /* change register `a' */
}
if (Lua.testTMode(op)) {
if (!(pc + 2 < pt.code.length)) return 0; /* check skip */
if (!(Lua.GET_OPCODE(pt.code[pc + 1]) == Lua.OP_JMP)) return 0;
}
switch (op) { switch (op) {
case Lua.OP_LOADBOOL: {
if (!(c == 0 || pc + 2 < pt.code.length)) return 0; /* check its jump */
break;
}
case Lua.OP_LOADNIL: { case Lua.OP_LOADNIL: {
if (a <= reg && reg <= b) int b = Lua.GETARG_B(i);
last = pc; /* set registers from `a' to `b' */ if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
setreg = pc;
break; break;
} }
case Lua.OP_GETUPVAL: case Lua.OP_TFORCALL: {
case Lua.OP_SETUPVAL: { if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
if (!(b < pt.nups)) return 0;
break;
}
case Lua.OP_GETGLOBAL:
case Lua.OP_SETGLOBAL: {
if (!(pt.k[b].isstring())) return 0;
break;
}
case Lua.OP_SELF: {
if (!checkreg(pt, a + 1)) return 0;
if (reg == a + 1)
last = pc;
break;
}
case Lua.OP_CONCAT: {
if (!(b < c)) return 0; /* at least two operands */
break;
}
case Lua.OP_TFORLOOP: {
if (!(c >= 1)) return 0; /* at least one result (control variable) */
if (!checkreg(pt, a + 2 + c)) return 0; /* space for results */
if (reg >= a + 2)
last = pc; /* affect all regs above its base */
break;
}
case Lua.OP_FORLOOP:
case Lua.OP_FORPREP:
if (!checkreg(pt, a + 3)) return 0;
/* go through */
case Lua.OP_JMP: {
int dest = pc + 1 + b;
/* not full check and jump is forward and do not skip `lastpc'? */
if (reg != Lua.NO_REG && pc < dest && dest <= lastpc)
pc += b; /* do the jump */
break; break;
} }
case Lua.OP_CALL: case Lua.OP_CALL:
case Lua.OP_TAILCALL: { case Lua.OP_TAILCALL: {
if (b != 0) { if (reg >= a) setreg = pc; /* affect all registers above base */
if (!checkreg(pt, a + b - 1)) return 0;
}
c--; /* c = num. returns */
if (c == Lua.LUA_MULTRET) {
if (!(checkopenop(pt, pc))) return 0;
} else if (c != 0)
if (!checkreg(pt, a + c - 1)) return 0;
if (reg >= a)
last = pc; /* affect all registers above base */
break; break;
} }
case Lua.OP_RETURN: { case Lua.OP_JMP: {
b--; /* b = num. returns */ int b = Lua.GETARG_sBx(i);
if (b > 0) int dest = pc + 1 + b;
if (!checkreg(pt, a + b - 1)) return 0; /* jump is forward and do not skip `lastpc'? */
if (pc < dest && dest <= lastpc)
pc += b; /* do the jump */
break; break;
} }
case Lua.OP_SETLIST: { case Lua.OP_TEST: {
if (b > 0) if (reg == a) setreg = pc; /* jumped code can change 'a' */
if (!checkreg(pt, a + b)) return 0;
if (c == 0)
pc++;
break;
}
case Lua.OP_CLOSURE: {
int nup, j;
if (!(b < pt.p.length)) return 0;
nup = pt.p[b].nups;
if (!(pc + nup < pt.code.length)) return 0;
for (j = 1; j <= nup; j++) {
int op1 = Lua.GET_OPCODE(pt.code[pc + j]);
if (!(op1 == Lua.OP_GETUPVAL || op1 == Lua.OP_MOVE)) return 0;
}
if (reg != Lua.NO_REG) /* tracing? */
pc += nup; /* do not 'execute' these pseudo-instructions */
break;
}
case Lua.OP_VARARG: {
if (!((pt.is_vararg & Lua.VARARG_ISVARARG) != 0
&& (pt.is_vararg & Lua.VARARG_NEEDSARG) == 0)) return 0;
b--;
if (b == Lua.LUA_MULTRET)
if (!(checkopenop(pt, pc))) return 0;
if (!checkreg(pt, a + b - 1)) return 0;
break; break;
} }
default: default:
if (Lua.testAMode(op) && reg == a) /* any instruction that set A */
setreg = pc;
break; break;
} }
} }
return pt.code[last]; return setreg;
} }
} }

View File

@@ -196,7 +196,7 @@ public class JavaBuilder {
main = new InstructionList(); main = new InstructionList();
// create the fields // create the fields
for ( int i=0; i<p.nups; i++ ) { for ( int i=0; i<p.upvalues.length; i++ ) {
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[i] ); boolean isrw = pi.isReadWriteUpvalue( pi.upvals[i] );
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE; Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
FieldGen fg = new FieldGen(0, uptype, upvalueName(i), cp); FieldGen fg = new FieldGen(0, uptype, upvalueName(i), cp);

View File

@@ -122,20 +122,6 @@ public class JavaGen {
builder.storeLocal( pc, a ); builder.storeLocal( pc, a );
break; break;
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
builder.loadEnv();
builder.loadConstant( p.k[bx] );
builder.getTable();
builder.storeLocal( pc, a );
break;
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
builder.loadEnv();
builder.loadConstant( p.k[bx] );
builder.loadLocal( pc, a );
builder.setTable();
break;
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(B):= nil */ case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(B):= nil */
builder.loadNil(); builder.loadNil();
for ( ; a<=b; a++ ) { for ( ; a<=b; a++ ) {
@@ -145,6 +131,13 @@ public class JavaGen {
} }
break; break;
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
builder.loadUpvalue( b );
loadLocalOrConstant( p, builder, pc, c );
builder.getTable();
builder.storeLocal( pc, a );
break;
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */ case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
builder.loadLocal( pc, b ); builder.loadLocal( pc, b );
loadLocalOrConstant( p, builder, pc, c ); loadLocalOrConstant( p, builder, pc, c );
@@ -152,6 +145,13 @@ public class JavaGen {
builder.storeLocal( pc, a ); builder.storeLocal( pc, a );
break; break;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
builder.loadUpvalue( a );
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.setTable();
break;
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */ case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
builder.loadLocal( pc, a ); builder.loadLocal( pc, a );
loadLocalOrConstant( p, builder, pc, b ); loadLocalOrConstant( p, builder, pc, b );
@@ -342,6 +342,9 @@ public class JavaGen {
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx); builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
break; 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: /* case Lua.OP_TFORLOOP: /*
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1), * 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) * R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
@@ -395,14 +398,11 @@ public class JavaGen {
} }
break; break;
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
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)) */
{ {
Prototype newp = p.p[bx]; Prototype newp = p.p[bx];
String protoname = closureName(classname, bx); String protoname = closureName(classname, bx);
int nup = newp.nups; int nup = newp.upvalues.length;
builder.closureCreate( protoname ); builder.closureCreate( protoname );
if ( nup > 0 ) if ( nup > 0 )
builder.dup(); builder.dup();

View File

@@ -164,7 +164,7 @@ 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_GETGLOBAL: /* A Bx R(A) := Gbl[Kst(Bx)] */ 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);
@@ -204,6 +204,13 @@ public class ProtoInfo {
if (!Lua.ISK(c)) v[c][pc].isreferenced = true; if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
break; break;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
break;
case Lua.OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */ case Lua.OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */
a = Lua.GETARG_A( ins ); a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins ); b = Lua.GETARG_B( ins );
@@ -295,6 +302,7 @@ public class ProtoInfo {
v[a+i][pc].isreferenced = true; v[a+i][pc].isreferenced = true;
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_TFORLOOP: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); 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++ */ if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */
a = Lua.GETARG_A( ins ); a = Lua.GETARG_A( ins );
@@ -311,7 +319,7 @@ public class ProtoInfo {
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].nups; nups = prototype.p[b].upvalues.length;
for ( int k=1; k<=nups; ++k ) { for ( int k=1; k<=nups; ++k ) {
int i = prototype.code[pc+k]; int i = prototype.code[pc+k];
if ( (i&4) == 0 ) { if ( (i&4) == 0 ) {
@@ -324,11 +332,6 @@ public class ProtoInfo {
propogateVars( v, pc, pc+k ); propogateVars( v, pc, pc+k );
pc += nups; pc += nups;
break; break;
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
a = Lua.GETARG_A( ins );
for ( ; a<m; a++ )
v[a][pc] = VarInfo.INVALID;
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 );
@@ -338,7 +341,6 @@ public class ProtoInfo {
v[a+i][pc].isreferenced = true; v[a+i][pc].isreferenced = true;
break; break;
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */ case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */ case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
a = Lua.GETARG_A( ins ); a = Lua.GETARG_A( ins );
@@ -402,9 +404,9 @@ public class ProtoInfo {
if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE ) { if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE ) {
int bx = Lua.GETARG_Bx(code[pc]); int bx = Lua.GETARG_Bx(code[pc]);
Prototype newp = prototype.p[bx]; Prototype newp = prototype.p[bx];
UpvalInfo[] newu = newp.nups>0? new UpvalInfo[newp.nups]: null; UpvalInfo[] newu = new UpvalInfo[newp.upvalues.length];
String newname = name + "$" + bx; String newname = name + "$" + bx;
for ( int j=0; j<newp.nups; ++j ) { for ( int j=0; j<newp.upvalues.length; ++j ) {
int i = code[++pc]; int i = code[++pc];
int b = Lua.GETARG_B(i); int b = Lua.GETARG_B(i);
newu[j] = (i&4) != 0? upvals[b]: findOpenUp(pc,b); newu[j] = (i&4) != 0? upvals[b]: findOpenUp(pc,b);

View File

@@ -5,23 +5,26 @@ package org.luaj.vm2.compiler;
public class CompilerUnitTests extends AbstractUnitTests { public class CompilerUnitTests extends AbstractUnitTests {
public CompilerUnitTests() { public CompilerUnitTests() {
super("lua5.1-tests.zip", "lua5.1-tests"); super("lua5.2.1-tests.zip", "lua5.2.1-tests");
} }
public void testAll() { doTest("all.lua"); } public void testAll() { doTest("all.lua"); }
public void testApi() { doTest("api.lua"); } public void testApi() { doTest("api.lua"); }
public void testAttrib() { doTest("attrib.lua"); } public void testAttrib() { doTest("attrib.lua"); }
public void testBig() { doTest("big.lua"); } public void testBig() { doTest("big.lua"); }
public void testBitwise() { doTest("bitwise.lua"); }
public void testCalls() { doTest("calls.lua"); } public void testCalls() { doTest("calls.lua"); }
public void testChecktable() { doTest("checktable.lua"); } public void testChecktable() { doTest("checktable.lua"); }
public void testClosure() { doTest("closure.lua"); } public void testClosure() { doTest("closure.lua"); }
public void testCode() { doTest("code.lua"); } public void testCode() { doTest("code.lua"); }
public void testConstruct() { doTest("constructs.lua"); } public void testConstruct() { doTest("constructs.lua"); }
public void testCoroutine() { doTest("coroutine.lua"); }
public void testDb() { doTest("db.lua"); } public void testDb() { doTest("db.lua"); }
public void testErrors() { doTest("errors.lua"); } public void testErrors() { doTest("errors.lua"); }
public void testEvents() { doTest("events.lua"); } public void testEvents() { doTest("events.lua"); }
public void testFiles() { doTest("files.lua"); } public void testFiles() { doTest("files.lua"); }
public void testGc() { doTest("gc.lua"); } public void testGc() { doTest("gc.lua"); }
public void testGoto() { doTest("goto.lua"); }
public void testLiterals() { doTest("literals.lua"); } public void testLiterals() { doTest("literals.lua"); }
public void testLocals() { doTest("locals.lua"); } public void testLocals() { doTest("locals.lua"); }
public void testMain() { doTest("main.lua"); } public void testMain() { doTest("main.lua"); }

Binary file not shown.