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 LocVars[] NOLOCVARS = {};
private static final LuaString[] NOSTRVALUES = {};
private static final Upvaldesc[] NOUPVALDESCS = {};
private static final int[] NOINTS = {};
/** Read buffer */
@@ -282,12 +283,24 @@ public class LoadState {
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
* @throws IOException if there is an i/o exception
*/
void loadDebug( Prototype f ) throws IOException {
f.source = loadString();
f.lineinfo = loadIntArray();
int n = loadInt();
f.locvars = n>0? new LocVars[n]: NOLOCVARS;
@@ -299,10 +312,9 @@ public class LoadState {
}
n = loadInt();
f.upvalues = n>0? new LuaString[n]: NOSTRVALUES;
for ( int i=0; i<n; i++ ) {
f.upvalues[i] = loadString();
}
f.upvalues = n>0? new Upvaldesc[n]: NOUPVALDESCS;
for ( int i=0; i<n; i++ )
f.upvalues[i] = new Upvaldesc(loadString(), false, i);
}
/**
@@ -319,12 +331,12 @@ public class LoadState {
f.source = p;
f.linedefined = loadInt();
f.lastlinedefined = loadInt();
f.nups = is.readUnsignedByte();
f.numparams = is.readUnsignedByte();
f.is_vararg = is.readUnsignedByte();
f.maxstacksize = is.readUnsignedByte();
f.code = loadIntArray();
loadConstants(f);
loadUpvalues(f);
loadDebug(f);
// TODO: add check here, for debugging purposes, I believe

View File

@@ -22,7 +22,7 @@
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 {
/** The local variable name */

View File

@@ -64,6 +64,7 @@ public class Lua {
public static final int iABC = 0;
public static final int iABx = 1;
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_Bx = (SIZE_C + SIZE_B);
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;
@@ -81,6 +83,7 @@ public class Lua {
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_Bx = POS_C;
public static final int POS_Ax = POS_A;
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_Bx = ((1<<SIZE_Bx)-1);
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_A = ((1<<SIZE_A)-1)<<POS_A;
@@ -113,6 +117,10 @@ public class Lua {
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) {
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_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_LOADNIL = 3; /* A B R(A) := ... := R(B) := nil */
public static final int OP_GETUPVAL = 4; /* A B R(A) := UpValue[B] */
public static final int OP_LOADKX = 2;/* A R(A) := Kst(extra arg) */
public static final int OP_LOADBOOL = 3;/* A B C R(A) := (Bool)B; if (C) pc++ */
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_GETTABLE = 6; /* A B C R(A) := R(B)[RK(C)] */
public static final int OP_GETTABUP = 6; /* A B C R(A) := UpValue[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_SETUPVAL = 8; /* 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_SETTABUP = 8; /* A B C UpValue[A][RK(B)] := RK(C) */
public static final int OP_SETUPVAL = 9; /* A B UpValue[B] := R(A) */
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_SUB = 13; /* 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_DIV = 15; /* 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_POW = 17; /* 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_NOT = 19; /* 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_ADD = 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 = 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 = 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 = 19; /* A B R(A) := -R(B) */
public static final int OP_NOT = 20; /* A B R(A) := not 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_LT = 24; /* A B C if ((RK(B) < RK(C)) ~= A) then 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 = 27; /* A C if not (R(A) <=> C) 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_TEST = 26; /* A C if not (R(A) <=> C) then pc++ */
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_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_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_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);
public static final int OP_FORLOOP = 32; /* A sBx R(A)+=R(A+2);
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++ */
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 = 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 OP_CLOSURE = 37; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
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. */
public static final int OP_GT = 63; // >
@@ -277,12 +288,13 @@ public class Lua {
/* T A B C mode opcode */
(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) | (OpArgN<<4) | (OpArgN<<2) | (iABx), /* OP_LOADKX */
(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) | (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) | (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) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SETTABLE */
(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_LT */
(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 */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_CALL */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_TAILCALL */
(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_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) | (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) | (iABC), /* OP_VARARG */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iAx), /* OP_EXTRAARG */
};
public static int getOpMode(int m) {

View File

@@ -21,9 +21,6 @@
******************************************************************************/
package org.luaj.vm2;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.luaj.vm2.LoadState.LuaCompiler;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.DebugLib;
@@ -101,15 +98,17 @@ public class LuaClosure extends LuaFunction {
}
/** Supply the initial environment */
public LuaClosure(Prototype p, LuaValue env) {
super( env );
this.p = p;
this.upValues = p.nups>0? new UpValue[p.nups]: NOUPVALUES;
this(p, p.upvalues.length, env);
}
protected LuaClosure(int nupvalues, LuaValue env) {
protected LuaClosure(Prototype p, int nupvalues, LuaValue env) {
super( env );
this.p = null;
this.upValues = nupvalues>0? new UpValue[nupvalues]: NOUPVALUES;
this.p = p;
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() {
@@ -233,16 +232,16 @@ public class LuaClosure extends LuaFunction {
stack[a] = upValues[i>>>23].getValue();
continue;
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
stack[a] = env.get(k[i>>>14]);
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
stack[a] = upValues[i>>>23].getValue().get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue;
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]);
continue;
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
env.set(k[i>>>14], stack[a]);
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
upValues[a].getValue().set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
@@ -423,6 +422,10 @@ public class LuaClosure extends LuaFunction {
}
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: /*
* 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)
@@ -462,21 +465,12 @@ public class LuaClosure extends LuaFunction {
}
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)) */
{
Prototype newp = p.p[i>>>14];
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++];
//b = B(i);
b = i>>>23;
newcl.upValues[j] = (i&4) != 0?
upValues[b]:
@@ -496,6 +490,12 @@ public class LuaClosure extends LuaFunction {
stack[a+j-1] = varargs.arg(j);
}
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 ) {

View File

@@ -188,6 +188,8 @@ public class LuaValue extends Varargs {
/** LuaValue array constant with no values */
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 */
public static final LuaString INDEX = valueOf("__index");

View File

@@ -136,6 +136,11 @@ public class Print extends Lua {
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
* @param f the {@link Prototype}
@@ -211,12 +216,12 @@ public class Print extends Lua {
case OP_SETUPVAL:
ps.print(" ; ");
if ( f.upvalues.length > b )
printValue(ps, f.upvalues[b]);
printUpvalue(ps, f.upvalues[b]);
else
ps.print( "-" );
break;
case OP_GETGLOBAL:
case OP_SETGLOBAL:
case OP_GETTABUP:
case OP_SETTABUP:
ps.print(" ; ");
printConstant( ps, f, bx );
break;

View File

@@ -42,10 +42,9 @@ public class Prototype {
public int[] lineinfo;
/* information about local variables */
public LocVars[] locvars;
/* upvalue names */
public LuaString[] upvalues;
/* upvalue information */
public Upvaldesc[] upvalues;
public LuaString source;
public int nups;
public int linedefined;
public int lastlinedefined;
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);
}
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 {
int i, n;
n = (strip) ? 0 : f.lineinfo.length;
dumpString(strip ? null: f.source);
n = strip ? 0 : f.lineinfo.length;
dumpInt(n);
for (i = 0; i < n; i++)
dumpInt(f.lineinfo[i]);
n = (strip) ? 0 : f.locvars.length;
n = strip ? 0 : f.locvars.length;
dumpInt(n);
for (i = 0; i < n; i++) {
LocVars lvi = f.locvars[i];
@@ -192,10 +202,10 @@ public class DumpState {
dumpInt(lvi.startpc);
dumpInt(lvi.endpc);
}
n = (strip) ? 0 : f.upvalues.length;
n = strip ? 0 : f.upvalues.length;
dumpInt(n);
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 {
@@ -205,12 +215,12 @@ public class DumpState {
dumpString(f.source);
dumpInt(f.linedefined);
dumpInt(f.lastlinedefined);
dumpChar(f.nups);
dumpChar(f.numparams);
dumpChar(f.is_vararg);
dumpChar(f.maxstacksize);
dumpCode(f);
dumpConstants(f);
dumpUpvalues(f);
dumpDebug(f);
}

View File

@@ -21,15 +21,15 @@
******************************************************************************/
package org.luaj.vm2.compiler;
import java.util.Hashtable;
import org.luaj.vm2.LuaBoolean;
import org.luaj.vm2.LuaDouble;
import org.luaj.vm2.LuaInteger;
import org.luaj.vm2.LocVars;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaNil;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.compiler.LexState.ConsControl;
@@ -37,22 +37,18 @@ import org.luaj.vm2.compiler.LexState.expdesc;
public class FuncState extends LuaC {
class upvaldesc {
short k;
short info;
};
static class BlockCnt {
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 */
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 */
// LTable h; /* table to find (and reuse) elements in `k' */
Hashtable htable; /* table to find (and reuse) elements in `k' */
LuaTable h; /* table to find (and reuse) elements in `k' */
FuncState prev; /* enclosing function */
LexState ls; /* lexical state */
LuaC L; /* compiler being invoked */
@@ -60,13 +56,13 @@ public class FuncState extends LuaC {
int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* `pc' of last `jump target' */
IntPtr jpc; /* list of pending jumps to `pc' */
int freereg; /* first free register */
int nk; /* number of elements in `k' */
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 nactvar; /* number of active local variables */
upvaldesc upvalues[] = new upvaldesc[LUAI_MAXUPVALUES]; /* upvalues */
short actvar[] = new short[LUAI_MAXVARS]; /* declared-variable stack */
short nups; /* number of upvalues */
short freereg; /* first free register */
FuncState() {
}
@@ -77,11 +73,11 @@ public class FuncState extends LuaC {
// =============================================================
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) {
return f.code[e.u.s.info];
return f.code[e.u.info];
}
int codeAsBx(int o, int A, int sBx) {
@@ -97,9 +93,18 @@ public class FuncState extends LuaC {
// from lparser.c
// =============================================================
LocVars getlocvar(int i) {
return f.locvars[actvar[i]];
/* check for repeated labels on the same block */
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) {
if ( v > l )
@@ -107,37 +112,47 @@ public class FuncState extends LuaC {
}
void errorlimit (int limit, String what) {
// TODO: report message logic.
String msg = (f.linedefined == 0) ?
L.pushfstring("main function has more than "+limit+" "+what) :
L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
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;
for (i = 0; i < f.nups; i++) {
if (upvalues[i].k == v.k && upvalues[i].info == v.u.s.info) {
_assert(f.upvalues[i] == name);
Upvaldesc[] up = f.upvalues;
for (i = 0; i < nups; i++)
if (up[i].name.eq_b(name))
return i;
return -1; /* not found */
}
}
/* new one */
checklimit(f.nups + 1, LUAI_MAXUPVALUES, "upvalues");
if ( f.upvalues == null || f.nups + 1 > f.upvalues.length)
f.upvalues = realloc( f.upvalues, f.nups*2+1 );
f.upvalues[f.nups] = name;
_assert (v.k == LexState.VLOCAL || v.k == LexState.VUPVAL);
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 newupvalue (LuaString name, expdesc v) {
checklimit(nups + 1, LUAI_MAXUPVAL, "upvalues");
if (f.upvalues == null || nups + 1 > f.upvalues.length)
f.upvalues = realloc( f.upvalues, nups > 0 ? nups*2 : 1 );
f.upvalues[nups] = new Upvaldesc(name, v.k == LexState.VLOCAL, v.u.info);
return nups++;
}
int searchvar(LuaString n) {
int i;
for (i = nactvar - 1; i >= 0; i--) {
if (n == getlocvar(i).varname)
if (n.eq_b(getlocvar(i).varname))
return i;
}
return -1; /* not found */
@@ -145,68 +160,89 @@ public class FuncState extends LuaC {
void markupval(int level) {
BlockCnt bl = this.bl;
while (bl != null && bl.nactvar > level)
while (bl.nactvar > level)
bl = bl.previous;
if (bl != null)
bl.upval = true;
}
int singlevaraux(LuaString n, expdesc var, int base) {
int v = searchvar(n); /* look up at current level */
static int singlevaraux(FuncState fs, LuaString n, expdesc var, int base) {
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) {
var.init(LexState.VLOCAL, v);
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;
} else { /* not found at current level; try upper one */
if (prev == null) { /* no more levels? */
/* default is global variable */
var.init(LexState.VGLOBAL, NO_REG);
return LexState.VGLOBAL;
} else { /* not found at current level; try upvalues */
int idx = fs.searchupvalue(n); /* try existing upvalues */
if (idx < 0) { /* not found? */
if (singlevaraux(fs.prev, n, var, 0) == LexState.VVOID) /* try upper levels */
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)
return LexState.VGLOBAL;
var.u.s.info = indexupvalue(n, var); /* else was LOCAL or UPVAL */
var.k = LexState.VUPVAL; /* upvalue in this level */
var.init(LexState.VUPVAL, idx);
return LexState.VUPVAL;
}
}
void enterblock (BlockCnt bl, boolean isbreakable) {
bl.breaklist.i = LexState.NO_JUMP;
bl.isbreakable = isbreakable;
bl.nactvar = this.nactvar;
/*
** "export" pending gotos to outer level, to check them against
** outer labels; if the block being exited has upvalues, and
** 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.previous = this.bl;
this.bl = bl;
_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() {
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;
ls.removevars(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.removevars(bl.nactvar);
_assert(bl.nactvar == this.nactvar);
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) {
@@ -215,7 +251,7 @@ public class FuncState extends LuaC {
this.exp2nextreg(cc.v);
cc.v.k = LexState.VVOID;
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 */
}
}
@@ -228,13 +264,13 @@ public class FuncState extends LuaC {
if (cc.tostore == 0) return;
if (hasmultret(cc.v.k)) {
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) */
}
else {
if (cc.v.k != LexState.VVOID)
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) {
this.getlabel();
this.concat(this.jpc, list);
@@ -428,21 +475,23 @@ public class FuncState extends LuaC {
void freeexp(expdesc e) {
if (e.k == LexState.VNONRELOC)
this.freereg(e.u.s.info);
this.freereg(e.u.info);
}
int addk(LuaValue v) {
int idx;
if (this.htable.containsKey(v)) {
idx = ((Integer) htable.get(v)).intValue();
if (this.h == null) {
this.h = new LuaTable();
} else {
idx = this.nk;
this.htable.put(v, new Integer(idx));
LuaValue idx = this.h.get(v);
if (idx.isnumber())
return idx.toint();
}
int idx = this.nk;
this.h.set(v, LuaValue.valueOf(idx));
final Prototype f = this.f;
if (f.k == null || nk + 1 >= f.k.length)
f.k = realloc( f.k, nk*2 + 1 );
f.k[this.nk++] = v;
}
return idx;
}
@@ -481,7 +530,7 @@ public class FuncState extends LuaC {
void setoneret(expdesc e) {
if (e.k == LexState.VCALL) { /* expression is an open function call? */
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) {
SETARG_B(this.getcodePtr(e), 2);
e.k = LexState.VRELOCABLE; /* can relocate its simple result */
@@ -495,20 +544,18 @@ public class FuncState extends LuaC {
break;
}
case LexState.VUPVAL: {
e.u.s.info = this.codeABC(OP_GETUPVAL, 0, e.u.s.info, 0);
e.k = LexState.VRELOCABLE;
break;
}
case LexState.VGLOBAL: {
e.u.s.info = this.codeABx(OP_GETGLOBAL, 0, e.u.s.info);
e.u.info = this.codeABC(OP_GETUPVAL, 0, e.u.info, 0);
e.k = LexState.VRELOCABLE;
break;
}
case LexState.VINDEXED: {
this.freereg(e.u.s.aux);
this.freereg(e.u.s.info);
e.u.s.info = this
.codeABC(OP_GETTABLE, 0, e.u.s.info, e.u.s.aux);
int op = OP_GETTABUP; /* assume 't' is in an upvalue */
this.freereg(e.u.ind_idx);
if (e.u.ind_vt == LexState.VLOCAL) { /* 't' is in a register? */
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;
break;
}
@@ -541,7 +588,7 @@ public class FuncState extends LuaC {
break;
}
case LexState.VK: {
this.codeABx(OP_LOADK, reg, e.u.s.info);
this.codeABx(OP_LOADK, reg, e.u.info);
break;
}
case LexState.VKNUM: {
@@ -554,8 +601,8 @@ public class FuncState extends LuaC {
break;
}
case LexState.VNONRELOC: {
if (reg != e.u.s.info)
this.codeABC(OP_MOVE, reg, e.u.s.info, 0);
if (reg != e.u.info)
this.codeABC(OP_MOVE, reg, e.u.info, 0);
break;
}
default: {
@@ -563,7 +610,7 @@ public class FuncState extends LuaC {
return; /* nothing to do... */
}
}
e.u.s.info = reg;
e.u.info = reg;
e.k = LexState.VNONRELOC;
}
@@ -577,7 +624,7 @@ public class FuncState extends LuaC {
void exp2reg(expdesc e, int reg) {
this.discharge2reg(e, reg);
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()) {
int _final; /* position after whole expression */
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);
}
e.f.i = e.t.i = LexState.NO_JUMP;
e.u.s.info = reg;
e.u.info = reg;
e.k = LexState.VNONRELOC;
}
@@ -609,14 +656,14 @@ public class FuncState extends LuaC {
this.dischargevars(e);
if (e.k == LexState.VNONRELOC) {
if (!e.hasjumps())
return e.u.s.info; /* exp is already in a register */
if (e.u.s.info >= this.nactvar) { /* reg. is not a local? */
this.exp2reg(e, e.u.s.info); /* put value on it */
return e.u.s.info;
return e.u.info; /* exp is already in a register */
if (e.u.info >= this.nactvar) { /* reg. is not a local? */
this.exp2reg(e, e.u.info); /* put value on it */
return e.u.info;
}
}
this.exp2nextreg(e); /* default */
return e.u.s.info;
return e.u.info;
}
void exp2val(expdesc e) {
@@ -634,17 +681,17 @@ public class FuncState extends LuaC {
case LexState.VFALSE:
case LexState.VNIL: {
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())
: this.boolK((e.k == LexState.VTRUE));
e.k = LexState.VK;
return RKASK(e.u.s.info);
return RKASK(e.u.info);
} else
break;
}
case LexState.VK: {
if (e.u.s.info <= MAXINDEXRK) /* constant fit in argC? */
return RKASK(e.u.s.info);
if (e.u.info <= MAXINDEXRK) /* constant fit in argC? */
return RKASK(e.u.info);
else
break;
}
@@ -659,22 +706,18 @@ public class FuncState extends LuaC {
switch (var.k) {
case LexState.VLOCAL: {
this.freeexp(ex);
this.exp2reg(ex, var.u.s.info);
this.exp2reg(ex, var.u.info);
return;
}
case LexState.VUPVAL: {
int e = this.exp2anyreg(ex);
this.codeABC(OP_SETUPVAL, e, var.u.s.info, 0);
break;
}
case LexState.VGLOBAL: {
int e = this.exp2anyreg(ex);
this.codeABx(OP_SETGLOBAL, e, var.u.s.info);
this.codeABC(OP_SETUPVAL, e, var.u.info, 0);
break;
}
case LexState.VINDEXED: {
int op = (var.u.ind_vt == LexState.VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
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;
}
default: {
@@ -691,14 +734,14 @@ public class FuncState extends LuaC {
this.freeexp(e);
func = this.freereg;
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);
e.u.s.info = func;
e.u.info = func;
e.k = LexState.VNONRELOC;
}
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()))
&& GET_OPCODE(pc.get()) != OP_TESTSET && Lua
.GET_OPCODE(pc.get()) != OP_TEST);
@@ -719,7 +762,7 @@ public class FuncState extends LuaC {
}
this.discharge2anyreg(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) {
@@ -738,7 +781,7 @@ public class FuncState extends LuaC {
}
case LexState.VJMP: {
this.invertjump(e);
pc = e.u.s.info;
pc = e.u.info;
break;
}
default: {
@@ -765,7 +808,7 @@ public class FuncState extends LuaC {
break;
}
case LexState.VJMP: {
pc = e.u.s.info;
pc = e.u.info;
break;
}
default: {
@@ -800,7 +843,7 @@ public class FuncState extends LuaC {
case LexState.VNONRELOC: {
this.discharge2anyreg(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;
break;
}
@@ -820,7 +863,9 @@ public class FuncState extends LuaC {
}
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;
}
@@ -881,7 +926,7 @@ public class FuncState extends LuaC {
this.freeexp(e2);
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;
}
}
@@ -898,7 +943,7 @@ public class FuncState extends LuaC {
o2 = temp; /* o1 <==> o2 */
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;
}
@@ -979,11 +1024,11 @@ public class FuncState extends LuaC {
this.exp2val(e2);
if (e2.k == LexState.VRELOCABLE
&& 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);
SETARG_B(this.getcodePtr(e2), e1.u.s.info);
SETARG_B(this.getcodePtr(e2), e1.u.info);
e1.k = LexState.VRELOCABLE;
e1.u.s.info = e2.u.s.info;
e1.u.info = e2.u.info;
} else {
this.exp2nextreg(e2); /* operand must be on the 'stack' */
this.codearith(OP_CONCAT, e1, e2);
@@ -1078,7 +1123,7 @@ public class FuncState extends LuaC {
this.codeABC(OP_SETLIST, base, b, 0);
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 */
VLOCAL = 6, /* info = local register */
VUPVAL = 7, /* info = index of upvalue in `upvalues' */
VGLOBAL = 8, /* info = index of table, aux = index of global name in `k' */
VINDEXED = 9, /* info = table register, aux = index register (or `k') */
VJMP = 10, /* info = instruction pc */
VRELOCABLE = 11, /* info = instruction pc */
VNONRELOC = 12, /* info = result register */
VCALL = 13, /* info = instruction pc */
VVARARG = 14; /* info = instruction pc */
VINDEXED = 8, /* info = table register, aux = index register (or `k') */
VJMP = 9, /* info = instruction pc */
VRELOCABLE = 10, /* info = instruction pc */
VNONRELOC = 11, /* info = result register */
VCALL = 12, /* info = instruction pc */
VVARARG = 13; /* info = instruction pc */
/* semantics information */
private static class SemInfo {
@@ -139,7 +138,9 @@ public class LexState {
InputStream z; /* input stream */
byte[] buff; /* buffer for tokens */
int nbuff; /* length of buffer */
Dyndata dyd; /* dynamic structures used by the parser */
LuaString source; /* current source name */
LuaString envn; /* environment variable name */
byte decpoint; /* locale decimal point */
/* ORDER RESERVED */
@@ -155,12 +156,12 @@ public class LexState {
final static int
/* terminal symbols denoted by reserved words */
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_IN=267, TK_LOCAL=268, TK_NIL=269, TK_NOT=270, TK_OR=271, TK_REPEAT=272,
TK_RETURN=273, TK_THEN=274, TK_TRUE=275, TK_UNTIL=276, TK_WHILE=277,
TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_GOTO=266, TK_IF=267,
TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273,
TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278,
/* other terminal symbols */
TK_CONCAT=278, TK_DOTS=279, TK_EQ=280, TK_GE=281, TK_LE=282, TK_NE=283,
TK_NUMBER=284, TK_NAME=285, TK_STRING=286, TK_EOS=287;
TK_CONCAT=279, TK_DOTS=280, TK_EQ=281, TK_GE=282, TK_LE=283, TK_NE=284,
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 NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED;
@@ -308,6 +309,7 @@ public class LexState {
this.linenumber = 1;
this.lastline = 1;
this.source = source;
this.envn = LuaValue.ENV; /* environment variable name */
this.nbuff = 0; /* initialize buffer */
this.current = firstByte; /* read first char */
this.skipShebang();
@@ -690,19 +692,27 @@ public class LexState {
// 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 {
int k; // expkind, from enumerated list, above
static class U { // originally a union
static class S {
int info, aux;
}
final S s = new S();
short ind_idx; // index (R/K)
short ind_t; // table(register or upvalue)
short ind_vt; // whether 't' is register (VLOCAL) or (UPVALUE)
private LuaValue _nval;
int info;
public void setNval(LuaValue r) {
_nval = r;
}
public LuaValue nval() {
return (_nval == null? LuaInteger.valueOf(s.info): _nval);
return (_nval == null? LuaInteger.valueOf(info): _nval);
}
};
final U u = new U();
@@ -712,7 +722,7 @@ public class LexState {
this.f.i = NO_JUMP;
this.t.i = NO_JUMP;
this.k = k;
this.u.s.info = i;
this.u.info = i;
}
boolean hasjumps() {
@@ -725,14 +735,51 @@ public class LexState {
public void setvalue(expdesc other) {
this.k = other.k;
this.u._nval = other.u._nval;
this.u.s.info = other.u.s.info;
this.u.s.aux = other.u.s.aux;
this.u.info = other.u.info;
this.u.ind_idx = other.u.ind_idx;
this.u.ind_t = other.u.ind_t;
this.u.ind_vt = other.u.ind_vt;
this.t.i = other.t.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) {
return ((k) == VCALL || (k) == VVARARG);
}
@@ -741,9 +788,21 @@ public class LexState {
name args description
------------------------------------------------------------------------*/
/*
* * prototypes for recursive non-terminal functions
*/
void anchor_token () {
/* 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) {
syntaxerror(L.pushfstring(LUA_QS(token2str(token)) + " expected"));
@@ -822,9 +881,11 @@ public class LexState {
}
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.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) {
@@ -844,8 +905,13 @@ public class LexState {
void singlevar(expdesc var) {
LuaString varname = this.str_checkname();
FuncState fs = this.fs;
if (fs.singlevaraux(varname, var, 1) == VGLOBAL)
var.u.s.info = fs.stringK(varname); /* info points to global name */
if (FuncState.singlevaraux(fs, varname, var, 1) == VVOID) { /* 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) {
@@ -881,21 +947,90 @@ public class LexState {
L.nCcalls--;
}
void pushclosure(FuncState func, expdesc v) {
void closegoto(int g, Labeldesc label) {
int i;
FuncState fs = this.fs;
Prototype f = fs.f;
if (f.p == null || fs.np + 1 > f.p.length)
f.p = LuaC.realloc( f.p, fs.np*2 + 1 );
f.p[fs.np++] = func.f;
v.init(VRELOCABLE, fs.codeABx(Lua.OP_CLOSURE, 0, fs.np - 1));
for (int i = 0; i < func.f.nups; i++) {
int o = (func.upvalues[i].k == VLOCAL) ? Lua.OP_MOVE
: Lua.OP_GETUPVAL;
fs.codeABC(o, 0, func.upvalues[i].info, 0);
Labeldesc[] gl = this.dyd.gt;
Labeldesc gt = gl[g];
LuaC._assert(gt.name.eq_b(label.name));
if (gt.nactvar < label.nactvar) {
LuaString vname = fs.getlocvar(gt.nactvar).varname;
String msg = L.pushfstring("<goto " + gt.name + "> at line "
+ gt.line + " jumps into the scope of local '"
+ vname.tojstring() + "'");
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;
Prototype f = new Prototype();
if ( this.fs!=null )
@@ -915,14 +1050,14 @@ public class LexState {
fs.nactvar = 0;
fs.bl = null;
f.maxstacksize = 2; /* registers 0/1 are always valid */
//fs.h = new LTable();
fs.htable = new Hashtable();
fs.enterblock(bl, false);
}
void close_func() {
FuncState fs = this.fs;
Prototype f = fs.f;
this.removevars(0);
fs.ret(0, 0);
fs.leaveblock();
fs.ret(0, 0); /* final return */
f.code = LuaC.realloc(f.code, 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.locvars = LuaC.realloc(f.locvars, 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 (fs.bl == null);
this.fs = fs.prev;
@@ -997,8 +1132,8 @@ public class LexState {
this.checknext('=');
rkkey = fs.exp2RK(key);
this.expr(val);
fs.codeABC(Lua.OP_SETTABLE, cc.t.u.s.info, rkkey, fs.exp2RK(val));
fs.freereg = reg; /* free registers */
fs.codeABC(Lua.OP_SETTABLE, cc.t.u.info, rkkey, fs.exp2RK(val));
fs.freereg = (short)reg; /* free registers */
}
void listfield (ConsControl cc) {
@@ -1106,7 +1241,8 @@ public class LexState {
void body(expdesc e, boolean needself, int line) {
/* body -> `(' parlist `)' chunk END */
FuncState new_fs = new FuncState();
open_func(new_fs);
BlockCnt bl = new BlockCnt();
open_func(new_fs, bl);
new_fs.f.linedefined = line;
this.checknext('(');
if (needself) {
@@ -1115,11 +1251,10 @@ public class LexState {
}
this.parlist();
this.checknext(')');
this.chunk();
this.statlist();
new_fs.f.lastlinedefined = this.linenumber;
this.check_match(TK_END, TK_FUNCTION, line);
this.close_func();
this.pushclosure(new_fs, e);
}
int explist1(expdesc v) {
@@ -1169,7 +1304,7 @@ public class LexState {
}
}
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))
nparams = Lua.LUA_MULTRET; /* open call */
else {
@@ -1179,7 +1314,7 @@ public class LexState {
}
f.init(VCALL, fs.codeABC(Lua.OP_CALL, base, nparams + 1, 2));
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 */
}
@@ -1427,11 +1562,12 @@ public class LexState {
*/
boolean block_follow (int token) {
switch (token) {
case TK_ELSE: case TK_ELSEIF: case TK_END:
case TK_UNTIL: case TK_EOS:
boolean block_follow (boolean withuntil) {
switch (t.token) {
case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOS:
return true;
case TK_UNTIL:
return withuntil;
default: return false;
}
}
@@ -1442,8 +1578,7 @@ public class LexState {
FuncState fs = this.fs;
BlockCnt bl = new BlockCnt();
fs.enterblock(bl, false);
this.chunk();
LuaC._assert(bl.breaklist.i == NO_JUMP);
this.statlist();
fs.leaveblock();
}
@@ -1467,22 +1602,25 @@ public class LexState {
*/
void check_conflict (LHS_assign lh, expdesc v) {
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;
for (; lh!=null; lh = lh.prev) {
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;
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;
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) {
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);
}
}
@@ -1532,21 +1670,44 @@ public class LexState {
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;
BlockCnt bl = fs.bl;
boolean upval = false;
while (bl != null && !bl.isbreakable) {
upval |= bl.upval;
bl = bl.previous;
}
if (bl == null)
this.syntaxerror("no loop to break");
if (upval)
fs.codeABC(Lua.OP_CLOSE, bl.nactvar, 0, 0);
fs.concat(bl.breaklist, fs.jump());
Labeldesc[] ll = dyd.label;
int l; /* index of new label being created */
fs.checkrepeated(ll, dyd.n_label, label); /* check for repeated labels */
checknext(TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
l = newlabelentry(LuaC.grow(ll, dyd.n_label+1), dyd.n_label++, label, line, fs.pc);
skipnoopstat(); /* skip other no-op statements */
if (block_follow(false)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
ll[l].nactvar = fs.bl.nactvar;
}
findgotos(ll[l]);
}
void whilestat (int line) {
@@ -1577,18 +1738,14 @@ public class LexState {
fs.enterblock(bl1, true); /* loop block */
fs.enterblock(bl2, false); /* scope block */
this.next(); /* skip REPEAT */
this.chunk();
this.statlist();
this.check_match(TK_UNTIL, TK_REPEAT, line);
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.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 */
}
@@ -1807,7 +1964,7 @@ public class LexState {
expdesc e = new expdesc();
int first, nret; /* registers with returned values */
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 */
else {
nret = this.explist1(e); /* optional return values */
@@ -1874,9 +2031,10 @@ public class LexState {
this.retstat();
return true; /* must be last statement */
}
case TK_BREAK: { /* stat -> breakstat */
case TK_BREAK:
case TK_GOTO: { /* stat -> breakstat */
this.next(); /* skip BREAK */
this.breakstat();
this.gotostat(fs.jump());
return true; /* must be last statement */
}
default: {
@@ -1886,18 +2044,32 @@ public class LexState {
}
}
void chunk() {
/* chunk -> { stat [`;'] } */
boolean islast = false;
this.enterlevel();
while (!islast && !block_follow(this.t.token)) {
islast = this.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 */
void statlist() {
/* statlist -> { stat [`;'] } */
while (!block_follow(true)) {
if (t.token == TK_RETURN) {
statement();
return; /* 'return' must be last statement */
}
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.LuaValue;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
import org.luaj.vm2.LoadState.LuaCompiler;
/**
@@ -83,7 +84,7 @@ public class LuaC extends Lua implements LuaCompiler {
}
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 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) );
}
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) {
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;
}
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) {
int[] a = new int[n];
if ( v != null )
@@ -206,23 +236,22 @@ public class LuaC extends Lua implements LuaCompiler {
(new LuaC(new Hashtable())).luaY_parser(firstByte, stream, name);
}
/** Parse the input */
private Prototype luaY_parser(int firstByte, InputStream z, String name) {
LexState lexstate = new LexState(this, z);
FuncState funcstate = new FuncState();
// lexstate.buff = buff;
lexstate.fs = funcstate;
lexstate.setinput( this, firstByte, z, (LuaString) LuaValue.valueOf(name) );
lexstate.open_func(funcstate);
/* main func. is always vararg */
funcstate.f.is_vararg = LuaC.VARARG_ISVARARG;
funcstate.f = new Prototype();
funcstate.f.source = (LuaString) LuaValue.valueOf(name);
lexstate.next(); /* read first token */
lexstate.chunk();
lexstate.check(LexState.TK_EOS);
lexstate.close_func();
lexstate.mainfunc(funcstate);
LuaC._assert (funcstate.prev == null);
LuaC._assert (funcstate.f.nups == 0);
LuaC._assert (lexstate.fs == null);
/* all scopes should be correctly finished */
LuaC._assert (lexstate.dyd == null
|| (lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0));
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 RETURN = valueOf("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 NUPS = valueOf("nups");
@@ -219,7 +220,7 @@ public class DebugLib extends VarArgFunction {
public LuaString[] getfunckind() {
if ( closure == null || pc<0 ) return null;
int stackpos = (closure.p.code[pc] >> 6) & 0xff;
return getobjname(this, stackpos);
return getobjname(this, pc, stackpos);
}
public String sourceline() {
if ( closure == null ) return func.tojstring();
@@ -500,7 +501,7 @@ public class DebugLib extends VarArgFunction {
break;
}
case 'u': {
info.set(NUPS, valueOf(c!=null? c.p.nups: 0));
info.set(NUPS, valueOf(c!=null? c.p.upvalues.length: 0));
break;
}
case 'n': {
@@ -604,7 +605,7 @@ public class DebugLib extends VarArgFunction {
static LuaString findupvalue(LuaClosure c, int up) {
if ( c.upValues != null && up > 0 && up <= c.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
return LuaString.valueOf( "."+up );
}
@@ -720,40 +721,53 @@ public class DebugLib extends VarArgFunction {
// return StrValue[] { name, namewhat } if found, null if not
static LuaString[] getobjname(DebugInfo di, int stackpos) {
LuaString name;
if (di.closure != null) { /* a Lua function? */
static LuaString[] getobjname(DebugInfo di, int lastpc, int reg) {
if (di.closure == null)
return null; /* Not a Lua function? */
Prototype p = di.closure.p;
int pc = di.pc; // currentpc(L, ci);
int i;// Instruction i;
name = p.getlocalname(stackpos + 1, pc);
LuaString name = p.getlocalname(reg + 1, pc);
if (name != null) /* is a 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)) {
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: {
int a = Lua.GETARG_A(i);
int b = Lua.GETARG_B(i); /* move from `b' to `a' */
if (b < a)
return getobjname(di, b); /* get name for `b' */
return getobjname(di, pc, b); /* get name for `b' */
break;
}
case Lua.OP_GETTABUP:
case Lua.OP_GETTABLE: {
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);
return new LuaString[] { name, FIELD };
return new LuaString[] { name, vn.eq_b(ENV)? GLOBAL: FIELD };
}
case Lua.OP_GETUPVAL: {
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 };
}
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: {
int k = Lua.GETARG_C(i); /* key index */
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.is_vararg & Lua.VARARG_NEEDSARG) == 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 (!(Lua.GET_OPCODE(pt.code[pt.code.length - 1]) == Lua.OP_RETURN)) return false;
return true;
@@ -816,162 +830,51 @@ public class DebugLib extends VarArgFunction {
return true;
}
// return last instruction, or 0 if error
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)
/*
** try to find last instruction before 'lastpc' that modified register 'reg'
*/
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++) {
int i = pt.code[pc];
int i = p.code[pc];
int op = Lua.GET_OPCODE(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) {
case Lua.OP_LOADBOOL: {
if (!(c == 0 || pc + 2 < pt.code.length)) return 0; /* check its jump */
break;
}
case Lua.OP_LOADNIL: {
if (a <= reg && reg <= b)
last = pc; /* set registers from `a' to `b' */
int b = Lua.GETARG_B(i);
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
setreg = pc;
break;
}
case Lua.OP_GETUPVAL:
case Lua.OP_SETUPVAL: {
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 */
case Lua.OP_TFORCALL: {
if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
break;
}
case Lua.OP_CALL:
case Lua.OP_TAILCALL: {
if (b != 0) {
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 */
if (reg >= a) setreg = pc; /* affect all registers above base */
break;
}
case Lua.OP_RETURN: {
b--; /* b = num. returns */
if (b > 0)
if (!checkreg(pt, a + b - 1)) return 0;
case Lua.OP_JMP: {
int b = Lua.GETARG_sBx(i);
int dest = pc + 1 + b;
/* jump is forward and do not skip `lastpc'? */
if (pc < dest && dest <= lastpc)
pc += b; /* do the jump */
break;
}
case Lua.OP_SETLIST: {
if (b > 0)
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;
case Lua.OP_TEST: {
if (reg == a) setreg = pc; /* jumped code can change 'a' */
break;
}
default:
if (Lua.testAMode(op) && reg == a) /* any instruction that set A */
setreg = pc;
break;
}
}
return pt.code[last];
return setreg;
}
}

View File

@@ -196,7 +196,7 @@ public class JavaBuilder {
main = new InstructionList();
// 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] );
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
FieldGen fg = new FieldGen(0, uptype, upvalueName(i), cp);

View File

@@ -122,20 +122,6 @@ public class JavaGen {
builder.storeLocal( pc, a );
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 */
builder.loadNil();
for ( ; a<=b; a++ ) {
@@ -145,6 +131,13 @@ public class JavaGen {
}
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)] */
builder.loadLocal( pc, b );
loadLocalOrConstant( p, builder, pc, c );
@@ -152,6 +145,13 @@ public class JavaGen {
builder.storeLocal( pc, a );
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) */
builder.loadLocal( pc, a );
loadLocalOrConstant( p, builder, pc, b );
@@ -342,6 +342,9 @@ public class JavaGen {
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
break;
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
throw new RuntimeException("Unimplemented OP_TFORCALL");
case Lua.OP_TFORLOOP: /*
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
@@ -395,14 +398,11 @@ public class JavaGen {
}
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)) */
{
Prototype newp = p.p[bx];
String protoname = closureName(classname, bx);
int nup = newp.nups;
int nup = newp.upvalues.length;
builder.closureCreate( protoname );
if ( nup > 0 )
builder.dup();

View File

@@ -164,7 +164,7 @@ public class ProtoInfo {
case Lua.OP_LOADK:/* A Bx R(A) := Kst(Bx) */
case Lua.OP_LOADBOOL:/* A B C R(A) := (Bool)B; if (C) pc++ */
case Lua.OP_GETUPVAL: /* A B R(A) := UpValue[B] */
case Lua.OP_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) */
a = Lua.GETARG_A( ins );
v[a][pc] = new VarInfo(a,pc);
@@ -204,6 +204,13 @@ public class ProtoInfo {
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
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) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
@@ -295,6 +302,7 @@ public class ProtoInfo {
v[a+i][pc].isreferenced = true;
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));
if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */
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)) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_Bx( ins );
nups = prototype.p[b].nups;
nups = prototype.p[b].upvalues.length;
for ( int k=1; k<=nups; ++k ) {
int i = prototype.code[pc+k];
if ( (i&4) == 0 ) {
@@ -324,11 +332,6 @@ public class ProtoInfo {
propogateVars( v, pc, pc+k );
pc += nups;
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 */
a = Lua.GETARG_A( ins );
@@ -338,7 +341,6 @@ public class ProtoInfo {
v[a+i][pc].isreferenced = true;
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_TEST: /* A C if not (R(A) <=> C) then pc++ */
a = Lua.GETARG_A( ins );
@@ -402,9 +404,9 @@ public class ProtoInfo {
if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE ) {
int bx = Lua.GETARG_Bx(code[pc]);
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;
for ( int j=0; j<newp.nups; ++j ) {
for ( int j=0; j<newp.upvalues.length; ++j ) {
int i = code[++pc];
int b = Lua.GETARG_B(i);
newu[j] = (i&4) != 0? upvals[b]: findOpenUp(pc,b);

View File

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

Binary file not shown.