Improve bytecode generation.
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
@@ -13,6 +12,7 @@ public class BasicBlock {
|
||||
int pc0,pc1; // range of program counter values for the block
|
||||
BasicBlock[] prev; // previous basic blocks (0-n of these)
|
||||
BasicBlock[] next; // next basic blocks (0, 1, or 2 of these)
|
||||
boolean islive; // true if this block is used
|
||||
|
||||
public BasicBlock(Prototype p, int pc0) {
|
||||
this.pc0 = this.pc1 = pc0;
|
||||
@@ -151,35 +151,30 @@ public class BasicBlock {
|
||||
}
|
||||
}
|
||||
|
||||
public static BasicBlock[] sortDepthFirst(BasicBlock[] blocks) {
|
||||
Vector list = new Vector();
|
||||
Hashtable seen = new Hashtable();
|
||||
Vector next = new Vector();
|
||||
BasicBlock b0,b1,b[];
|
||||
|
||||
public static BasicBlock[] findLiveBlocks(BasicBlock[] blocks) {
|
||||
// add reachable blocks
|
||||
Vector next = new Vector ();
|
||||
next.addElement( blocks[0] );
|
||||
seen.put( blocks[0], Boolean.TRUE );
|
||||
while ( (b = toBasicBlockArray(next)) != null ) {
|
||||
next.clear();
|
||||
for ( int i=0; i<b.length; i++ ) {
|
||||
list.addElement( b0 = b[i] );
|
||||
for ( int k=0, n=b0.next!=null? b0.next.length: 0; k<n; k++ ) {
|
||||
if ( seen.get( b1 = b0.next[k] ) == null ) {
|
||||
seen.put( b1, Boolean.TRUE );
|
||||
next.addElement( b1 );
|
||||
}
|
||||
}
|
||||
while ( ! next.isEmpty() ) {
|
||||
BasicBlock b = (BasicBlock) next.elementAt(0);
|
||||
next.removeElementAt(0);
|
||||
if ( ! b.islive ) {
|
||||
b.islive = true;
|
||||
for ( int i=0, n=b.next!=null? b.next.length: 0; i<n; i++ )
|
||||
if ( ! b.next[i].islive )
|
||||
next.addElement( b.next[i] );
|
||||
}
|
||||
}
|
||||
return toBasicBlockArray(list);
|
||||
}
|
||||
|
||||
private static BasicBlock[] toBasicBlockArray(Vector list) {
|
||||
if ( list.size() <= 0 )
|
||||
return null;
|
||||
// create list in natural order
|
||||
Vector list = new Vector();
|
||||
for ( int i=0; i<blocks.length; i=blocks[i].pc1+1 )
|
||||
if ( blocks[i].islive )
|
||||
list.addElement(blocks[i]);
|
||||
|
||||
// convert to array
|
||||
BasicBlock[] array = new BasicBlock[list.size()];
|
||||
list.copyInto(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,393 +66,375 @@ public class JavaGen {
|
||||
Prototype p = pi.prototype;
|
||||
int vresultbase = -1;
|
||||
|
||||
for ( int pc=0, n=p.code.length; pc<n; pc++ ) {
|
||||
for ( int bi=0; bi<pi.blocklist.length; bi++ ) {
|
||||
BasicBlock b0 = pi.blocklist[bi];
|
||||
|
||||
// skip dead blocks
|
||||
BasicBlock b0 = pi.blocks[pc];
|
||||
if ( b0.pc0>0 && b0.prev == null ) {
|
||||
pc = b0.pc1;
|
||||
continue;
|
||||
// convert upvalues that are phi-variables
|
||||
for ( int slot=0; slot<p.maxstacksize; slot++ ) {
|
||||
int pc = b0.pc0;
|
||||
boolean c = pi.isUpvalueCreate(pc, slot);
|
||||
if ( c && pi.vars[slot][pc].isPhiVar() )
|
||||
builder.convertToUpvalue(pc, slot);
|
||||
}
|
||||
|
||||
int pc0 = pc; // closure changes pc
|
||||
int ins = p.code[pc];
|
||||
final int o = Lua.GET_OPCODE(ins);
|
||||
int a = Lua.GETARG_A(ins);
|
||||
int b = Lua.GETARG_B(ins);
|
||||
int bx = Lua.GETARG_Bx(ins);
|
||||
int sbx = Lua.GETARG_sBx(ins);
|
||||
int c = Lua.GETARG_C(ins);
|
||||
for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) {
|
||||
|
||||
switch ( o ) {
|
||||
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
|
||||
builder.loadUpvalue( b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
int pc0 = pc; // closure changes pc
|
||||
int ins = p.code[pc];
|
||||
final int o = Lua.GET_OPCODE(ins);
|
||||
int a = Lua.GETARG_A(ins);
|
||||
int b = Lua.GETARG_B(ins);
|
||||
int bx = Lua.GETARG_Bx(ins);
|
||||
int sbx = Lua.GETARG_sBx(ins);
|
||||
int c = Lua.GETARG_C(ins);
|
||||
|
||||
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||
builder.storeUpvalue( pc, b, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
|
||||
builder.newTable( b, c );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_MOVE:/* A B R(A):= R(B) */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_UNM: /* A B R(A):= -R(B) */
|
||||
case Lua.OP_NOT: /* A B R(A):= not R(B) */
|
||||
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.unaryop( o );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
|
||||
builder.loadConstant( p.k[bx] );
|
||||
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++ ) {
|
||||
if ( a < b )
|
||||
builder.dup();
|
||||
switch ( o ) {
|
||||
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
|
||||
builder.loadUpvalue( b );
|
||||
builder.storeLocal( pc, a );
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
|
||||
builder.loadLocal( pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.getTable();
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||
builder.storeUpvalue( pc, b, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
|
||||
builder.loadLocal( pc, a );
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.setTable();
|
||||
break;
|
||||
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
|
||||
builder.newTable( b, c );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
|
||||
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
|
||||
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
|
||||
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
|
||||
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
|
||||
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.binaryop( o );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
|
||||
builder.loadLocal(pc,b);
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a+1);
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.getTable();
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
|
||||
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
|
||||
builder.newBuffer();
|
||||
while ( b<=c ) {
|
||||
builder.loadLocal(pc, b++);
|
||||
builder.appendBuffer();
|
||||
}
|
||||
builder.tostring();
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
|
||||
builder.loadBoolean( b!=0 );
|
||||
builder.storeLocal( pc, a );
|
||||
if ( c!=0 )
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_JMP: /* sBx pc+=sBx */
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.compareop(o);
|
||||
builder.addBranch(pc, (a!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||
builder.loadLocal( pc, a );
|
||||
builder.toBoolean();
|
||||
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.toBoolean();
|
||||
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
builder.loadLocal( pc, b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
|
||||
// load function
|
||||
builder.loadLocal(pc, a);
|
||||
|
||||
// load args
|
||||
int narg = b - 1;
|
||||
switch ( narg ) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
for ( int i=1; i<b; i++ )
|
||||
builder.loadLocal(pc, a+i);
|
||||
case Lua.OP_MOVE:/* A B R(A):= R(B) */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
default: // fixed arg count > 3
|
||||
builder.newVarargs( pc, a+1, b-1 );
|
||||
narg = -1;
|
||||
break;
|
||||
case -1: // prev vararg result
|
||||
loadVarargResults( builder, pc, a+1, vresultbase );
|
||||
narg = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// call or invoke
|
||||
boolean useinvoke = narg<0 || c<1 || c>2;
|
||||
if ( useinvoke )
|
||||
builder.invoke(narg);
|
||||
else
|
||||
builder.call(narg);
|
||||
|
||||
// handle results
|
||||
switch ( c ) {
|
||||
case 1:
|
||||
builder.pop();
|
||||
case Lua.OP_UNM: /* A B R(A):= -R(B) */
|
||||
case Lua.OP_NOT: /* A B R(A):= not R(B) */
|
||||
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.unaryop( o );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
case 2:
|
||||
if ( useinvoke )
|
||||
builder.arg( 1 );
|
||||
|
||||
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
|
||||
builder.loadConstant( p.k[bx] );
|
||||
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++ ) {
|
||||
if ( a < b )
|
||||
builder.dup();
|
||||
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 );
|
||||
builder.getTable();
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
|
||||
builder.loadLocal( pc, a );
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.setTable();
|
||||
break;
|
||||
|
||||
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
|
||||
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
|
||||
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
|
||||
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
|
||||
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
|
||||
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.binaryop( o );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
|
||||
builder.loadLocal(pc,b);
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a+1);
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.getTable();
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
default: // fixed result count - unpack args
|
||||
for ( int i=1; i<c; i++ ) {
|
||||
if ( i+1 < c )
|
||||
builder.dup();
|
||||
builder.arg( i );
|
||||
builder.storeLocal(pc, a+i-1);
|
||||
|
||||
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
|
||||
builder.newBuffer();
|
||||
while ( b<=c ) {
|
||||
builder.loadLocal(pc, b++);
|
||||
builder.appendBuffer();
|
||||
}
|
||||
builder.tostring();
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
|
||||
builder.loadBoolean( b!=0 );
|
||||
builder.storeLocal( pc, a );
|
||||
if ( c!=0 )
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_JMP: /* sBx pc+=sBx */
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.compareop(o);
|
||||
builder.addBranch(pc, (a!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||
builder.loadLocal( pc, a );
|
||||
builder.toBoolean();
|
||||
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.toBoolean();
|
||||
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
builder.loadLocal( pc, b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
|
||||
// load function
|
||||
builder.loadLocal(pc, a);
|
||||
|
||||
// load args
|
||||
int narg = b - 1;
|
||||
switch ( narg ) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
for ( int i=1; i<b; i++ )
|
||||
builder.loadLocal(pc, a+i);
|
||||
break;
|
||||
default: // fixed arg count > 3
|
||||
builder.newVarargs( pc, a+1, b-1 );
|
||||
narg = -1;
|
||||
break;
|
||||
case -1: // prev vararg result
|
||||
loadVarargResults( builder, pc, a+1, vresultbase );
|
||||
narg = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// call or invoke
|
||||
boolean useinvoke = narg<0 || c<1 || c>2;
|
||||
if ( useinvoke )
|
||||
builder.invoke(narg);
|
||||
else
|
||||
builder.call(narg);
|
||||
|
||||
// handle results
|
||||
switch ( c ) {
|
||||
case 1:
|
||||
builder.pop();
|
||||
break;
|
||||
case 2:
|
||||
if ( useinvoke )
|
||||
builder.arg( 1 );
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
default: // fixed result count - unpack args
|
||||
for ( int i=1; i<c; i++ ) {
|
||||
if ( i+1 < c )
|
||||
builder.dup();
|
||||
builder.arg( i );
|
||||
builder.storeLocal(pc, a+i-1);
|
||||
}
|
||||
break;
|
||||
case 0: // vararg result
|
||||
vresultbase = a;
|
||||
builder.storeVarresult();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0: // vararg result
|
||||
vresultbase = a;
|
||||
builder.storeVarresult();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
|
||||
// load function
|
||||
builder.loadLocal(pc, a);
|
||||
// load function
|
||||
builder.loadLocal(pc, a);
|
||||
|
||||
// load args
|
||||
switch ( b ) {
|
||||
case 1:
|
||||
builder.loadNone();
|
||||
break;
|
||||
case 2:
|
||||
builder.loadLocal(pc, a+1);
|
||||
break;
|
||||
default: // fixed arg count > 1
|
||||
builder.newVarargs( pc, a+1, b-1 );
|
||||
break;
|
||||
case 0: // prev vararg result
|
||||
loadVarargResults( builder, pc, a+1, vresultbase );
|
||||
break;
|
||||
}
|
||||
builder.newTailcallVarargs();
|
||||
builder.areturn();
|
||||
break;
|
||||
|
||||
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
if ( c == 1 ) {
|
||||
builder.loadNone();
|
||||
} else {
|
||||
// load args
|
||||
switch ( b ) {
|
||||
case 0: loadVarargResults( builder, pc, a, vresultbase ); break;
|
||||
case 1: builder.loadNone(); break;
|
||||
case 2: builder.loadLocal(pc, a); break;
|
||||
default: builder.newVarargs(pc, a, b-1); break;
|
||||
case 1:
|
||||
builder.loadNone();
|
||||
break;
|
||||
case 2:
|
||||
builder.loadLocal(pc, a+1);
|
||||
break;
|
||||
default: // fixed arg count > 1
|
||||
builder.newVarargs( pc, a+1, b-1 );
|
||||
break;
|
||||
case 0: // prev vararg result
|
||||
loadVarargResults( builder, pc, a+1, vresultbase );
|
||||
break;
|
||||
}
|
||||
}
|
||||
builder.areturn();
|
||||
break;
|
||||
builder.newTailcallVarargs();
|
||||
builder.areturn();
|
||||
break;
|
||||
|
||||
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.binaryop( Lua.OP_SUB );
|
||||
builder.storeLocal(pc, a);
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.binaryop( Lua.OP_ADD );
|
||||
builder.dup();
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a);
|
||||
builder.storeLocal(pc, a+3);
|
||||
builder.loadLocal(pc, a+1); // limit
|
||||
builder.loadLocal(pc, a+2); // step
|
||||
builder.testForLoop();
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_TFORLOOP: /*
|
||||
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
|
||||
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
|
||||
* else pc++
|
||||
*/
|
||||
// v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
|
||||
// if ( (o=v.arg1()).isnil() )
|
||||
// ++pc;
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+1);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.invoke(2); // varresult on stack
|
||||
builder.dup();
|
||||
builder.storeVarresult();
|
||||
builder.arg( 1 );
|
||||
builder.isNil();
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+2);
|
||||
|
||||
// a[2] = a[3] = v[1], leave varargs on stack
|
||||
builder.createUpvalues(pc, a+3, c);
|
||||
builder.loadVarresult();
|
||||
if (c>=2)
|
||||
builder.dup();
|
||||
builder.arg( 1 );
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a+2);
|
||||
builder.storeLocal(pc, a+3);
|
||||
|
||||
// v[2]..v[c], use varargs from stack
|
||||
for ( int j=2; j<=c; j++ ) {
|
||||
if ( j<c )
|
||||
builder.dup();
|
||||
builder.arg( j );
|
||||
builder.storeLocal(pc, a+2+j);
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
|
||||
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1;
|
||||
builder.loadLocal( pc, a );
|
||||
if ( b == 0 ) {
|
||||
int nstack = vresultbase - (a+1);
|
||||
if ( nstack > 0 ) {
|
||||
builder.setlistStack( pc, a+1, index0, nstack );
|
||||
index0 += nstack;
|
||||
}
|
||||
builder.setlistVarargs( index0, vresultbase );
|
||||
} else {
|
||||
builder.setlistStack( pc, a+1, index0, b );
|
||||
builder.pop();
|
||||
}
|
||||
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)) */
|
||||
{
|
||||
/*
|
||||
String protoname = closureName(classname, bx);
|
||||
int nups = p.p[bx].nups;
|
||||
for ( int k=1; k<=nups; ++k ) {
|
||||
builder.dup();
|
||||
int i = p.code[pc+k];
|
||||
b = Lua.GETARG_B(i);
|
||||
if ( (i&4) == 0 ) {
|
||||
builder.closureInitUpvalueFromUpvalue( protoname, k-1, b );
|
||||
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
if ( c == 1 ) {
|
||||
builder.loadNone();
|
||||
} else {
|
||||
builder.closureInitUpvalueFromLocal( protoname, k-1, pc, b );
|
||||
}
|
||||
}
|
||||
v[a][pc] = new VarInfo(a,pc);
|
||||
for ( int k=1; k<=nups; ++k ) {
|
||||
for ( int j=0; j<m; j++ )
|
||||
v[j][pc+k] = v[j][pc];
|
||||
}
|
||||
pc += nups;
|
||||
/*/
|
||||
|
||||
|
||||
Prototype newp = p.p[bx];
|
||||
String protoname = closureName(classname, bx);
|
||||
int nup = newp.nups;
|
||||
builder.closureCreate( protoname );
|
||||
if ( nup > 0 )
|
||||
builder.dup();
|
||||
builder.storeLocal( pc, a );
|
||||
if ( nup > 0 ) {
|
||||
for ( int up=0; up<nup; ++up ) {
|
||||
if ( up+1 < nup )
|
||||
builder.dup();
|
||||
ins = p.code[pc+up+1];
|
||||
b = Lua.GETARG_B(ins);
|
||||
if ( (ins&4) != 0 ) {
|
||||
builder.closureInitUpvalueFromUpvalue( protoname, up, b );
|
||||
} else {
|
||||
builder.closureInitUpvalueFromLocal( protoname, up, pc, b );
|
||||
switch ( b ) {
|
||||
case 0: loadVarargResults( builder, pc, a, vresultbase ); break;
|
||||
case 1: builder.loadNone(); break;
|
||||
case 2: builder.loadLocal(pc, a); break;
|
||||
default: builder.newVarargs(pc, a, b-1); break;
|
||||
}
|
||||
}
|
||||
pc += nup;
|
||||
}
|
||||
//*/
|
||||
break;
|
||||
}
|
||||
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
if ( b == 0 ) {
|
||||
builder.loadVarargs();
|
||||
builder.storeVarresult();
|
||||
vresultbase = a;
|
||||
} else {
|
||||
for ( int i=1; i<b; ++a, ++i ) {
|
||||
builder.loadVarargs( i );
|
||||
builder.storeLocal(pc, a);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
builder.areturn();
|
||||
break;
|
||||
|
||||
// let builder process branch instructions
|
||||
builder.onEndOfLuaInstruction( pc0 );
|
||||
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.binaryop( Lua.OP_SUB );
|
||||
builder.storeLocal(pc, a);
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.binaryop( Lua.OP_ADD );
|
||||
builder.dup();
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a);
|
||||
builder.storeLocal(pc, a+3);
|
||||
builder.loadLocal(pc, a+1); // limit
|
||||
builder.loadLocal(pc, a+2); // step
|
||||
builder.testForLoop();
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_TFORLOOP: /*
|
||||
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
|
||||
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
|
||||
* else pc++
|
||||
*/
|
||||
// v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
|
||||
// if ( (o=v.arg1()).isnil() )
|
||||
// ++pc;
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+1);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.invoke(2); // varresult on stack
|
||||
builder.dup();
|
||||
builder.storeVarresult();
|
||||
builder.arg( 1 );
|
||||
builder.isNil();
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+2);
|
||||
|
||||
// a[2] = a[3] = v[1], leave varargs on stack
|
||||
builder.createUpvalues(pc, a+3, c);
|
||||
builder.loadVarresult();
|
||||
if (c>=2)
|
||||
builder.dup();
|
||||
builder.arg( 1 );
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a+2);
|
||||
builder.storeLocal(pc, a+3);
|
||||
|
||||
// v[2]..v[c], use varargs from stack
|
||||
for ( int j=2; j<=c; j++ ) {
|
||||
if ( j<c )
|
||||
builder.dup();
|
||||
builder.arg( j );
|
||||
builder.storeLocal(pc, a+2+j);
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
|
||||
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1;
|
||||
builder.loadLocal( pc, a );
|
||||
if ( b == 0 ) {
|
||||
int nstack = vresultbase - (a+1);
|
||||
if ( nstack > 0 ) {
|
||||
builder.setlistStack( pc, a+1, index0, nstack );
|
||||
index0 += nstack;
|
||||
}
|
||||
builder.setlistVarargs( index0, vresultbase );
|
||||
} else {
|
||||
builder.setlistStack( pc, a+1, index0, b );
|
||||
builder.pop();
|
||||
}
|
||||
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;
|
||||
builder.closureCreate( protoname );
|
||||
if ( nup > 0 )
|
||||
builder.dup();
|
||||
builder.storeLocal( pc, a );
|
||||
if ( nup > 0 ) {
|
||||
for ( int up=0; up<nup; ++up ) {
|
||||
if ( up+1 < nup )
|
||||
builder.dup();
|
||||
ins = p.code[pc+up+1];
|
||||
b = Lua.GETARG_B(ins);
|
||||
if ( (ins&4) != 0 ) {
|
||||
builder.closureInitUpvalueFromUpvalue( protoname, up, b );
|
||||
} else {
|
||||
builder.closureInitUpvalueFromLocal( protoname, up, pc, b );
|
||||
}
|
||||
}
|
||||
pc += nup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
if ( b == 0 ) {
|
||||
builder.loadVarargs();
|
||||
builder.storeVarresult();
|
||||
vresultbase = a;
|
||||
} else {
|
||||
for ( int i=1; i<b; ++a, ++i ) {
|
||||
builder.loadVarargs( i );
|
||||
builder.storeLocal(pc, a);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// let builder process branch instructions
|
||||
builder.onEndOfLuaInstruction( pc0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ public class ProtoInfo {
|
||||
public final UpvalInfo[] upvals; // from outer scope
|
||||
public final UpvalInfo[][] openups; // per slot, upvalues allocated by this prototype
|
||||
|
||||
|
||||
public ProtoInfo(Prototype p, String name) {
|
||||
this(p,name,null);
|
||||
}
|
||||
@@ -35,8 +34,7 @@ public class ProtoInfo {
|
||||
|
||||
// find basic blocks
|
||||
this.blocks = BasicBlock.findBasicBlocks(p);
|
||||
this.blocklist = BasicBlock.sortDepthFirst(blocks);
|
||||
|
||||
this.blocklist = BasicBlock.findLiveBlocks(blocks);
|
||||
|
||||
// params are inputs to first block
|
||||
this.params = new VarInfo[p.maxstacksize];
|
||||
@@ -65,8 +63,9 @@ public class ProtoInfo {
|
||||
sb.append( " up["+i+"]: "+upvals[i]+"\n" );
|
||||
|
||||
// basic blocks
|
||||
for ( int pc0=blocks[0].pc0; pc0<prototype.code.length; pc0=blocks[pc0].pc1+1 ) {
|
||||
BasicBlock b = blocks[pc0];
|
||||
for ( int i=0; i<blocklist.length; i++ ) {
|
||||
BasicBlock b = blocklist[i];
|
||||
int pc0 = b.pc0;
|
||||
sb.append( " block "+b.toString() );
|
||||
appendOpenUps( sb, -1 );
|
||||
|
||||
@@ -143,19 +142,18 @@ public class ProtoInfo {
|
||||
if ( v[slot][bp.pc1] == VarInfo.INVALID )
|
||||
var = VarInfo.INVALID;
|
||||
}
|
||||
if ( var == null )
|
||||
var = VarInfo.PHI(this, slot, b0.pc0);
|
||||
}
|
||||
if ( var == null )
|
||||
var = VarInfo.PHI(this, slot, b0.pc0);
|
||||
v[slot][b0.pc0] = var;
|
||||
}
|
||||
|
||||
// process instructions for this basic block
|
||||
for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) {
|
||||
|
||||
// propogate previous for all but block boundaries
|
||||
if ( pc>b0.pc0 )
|
||||
for ( int j=0; j<m; j++ )
|
||||
v[j][pc] = v[j][pc-1];
|
||||
// propogate previous values except at block boundaries
|
||||
if ( pc > b0.pc0 )
|
||||
propogateVars( v, pc-1, pc );
|
||||
|
||||
int a,b,c,nups;
|
||||
int ins = prototype.code[pc];
|
||||
@@ -322,10 +320,8 @@ public class ProtoInfo {
|
||||
}
|
||||
}
|
||||
v[a][pc] = new VarInfo(a,pc);
|
||||
for ( int k=1; k<=nups; ++k ) {
|
||||
for ( int j=0; j<m; j++ )
|
||||
v[j][pc+k] = v[j][pc];
|
||||
}
|
||||
for ( int k=1; k<=nups; k++ )
|
||||
propogateVars( v, pc, pc+k );
|
||||
pc += nups;
|
||||
break;
|
||||
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
|
||||
@@ -369,11 +365,16 @@ public class ProtoInfo {
|
||||
return v;
|
||||
}
|
||||
|
||||
private static void propogateVars(VarInfo[][] v, int pcfrom, int pcto) {
|
||||
for ( int j=0, m=v.length; j<m; j++ )
|
||||
v[j][pcto] = v[j][pcfrom];
|
||||
}
|
||||
|
||||
private void replaceTrivialPhiVariables() {
|
||||
for ( int i=0; i<blocklist.length; i++ ) {
|
||||
BasicBlock b0 = blocklist[i];
|
||||
for ( int slot=0; slot<prototype.maxstacksize; slot++ ) {
|
||||
VarInfo vold = vars[slot][b0.pc1];
|
||||
VarInfo vold = vars[slot][b0.pc0];
|
||||
VarInfo vnew = vold.resolvePhiVariableValues();
|
||||
if ( vnew != null )
|
||||
substituteVariable( slot, vold, vnew );
|
||||
@@ -443,7 +444,7 @@ public class ProtoInfo {
|
||||
|
||||
public boolean isUpvalueRefer(int pc, int slot) {
|
||||
// special case when both refer and assign in same instruction
|
||||
if ( pc >= 0 && vars[slot][pc] != null && vars[slot][pc].pc == pc )
|
||||
if ( pc > 0 && vars[slot][pc] != null && vars[slot][pc].pc == pc && vars[slot][pc-1] != null )
|
||||
pc -= 1;
|
||||
VarInfo v = pc<0? params[slot]: vars[slot][pc];
|
||||
return v != null && v.upvalue != null && v.upvalue.rw;
|
||||
|
||||
@@ -63,6 +63,10 @@ public class VarInfo {
|
||||
vars.add(this);
|
||||
}
|
||||
|
||||
public boolean isPhiVar() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final class PhiVarInfo extends VarInfo {
|
||||
private final ProtoInfo pi;
|
||||
VarInfo[] values;
|
||||
@@ -72,6 +76,10 @@ public class VarInfo {
|
||||
this.pi = pi;
|
||||
}
|
||||
|
||||
public boolean isPhiVar() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append( super.toString() );
|
||||
@@ -108,6 +116,8 @@ public class VarInfo {
|
||||
|
||||
protected void collectUniqueValues(Set visitedBlocks, Set vars) {
|
||||
BasicBlock b = pi.blocks[pc];
|
||||
if ( pc == 0 )
|
||||
vars.add(pi.params[slot]);
|
||||
for (int i = 0, n = b.prev != null ? b.prev.length : 0; i < n; i++) {
|
||||
BasicBlock bp = b.prev[i];
|
||||
if (!visitedBlocks.contains(bp)) {
|
||||
|
||||
@@ -501,5 +501,53 @@ public class FragmentsTest extends TestSuite {
|
||||
" return c,b,a\n" +
|
||||
"end\n" );
|
||||
}
|
||||
|
||||
public void testPhiUpvalue() {
|
||||
runFragment( LuaValue.valueOf(6),
|
||||
"local a = foo or 0\n"+
|
||||
"local function b(c)\n"+
|
||||
" if c > a then a = c end\n" +
|
||||
" return a\n"+
|
||||
"end\n" +
|
||||
"b(6)\n" +
|
||||
"return a\n" );
|
||||
}
|
||||
|
||||
public void testAssignReferUpvalues() {
|
||||
runFragment( LuaValue.valueOf(123),
|
||||
"local entity = 234\n" +
|
||||
"local function c()\n" +
|
||||
" return entity\n" +
|
||||
"end\n" +
|
||||
"entity = (a == b) and 123\n" +
|
||||
"if entity then\n" +
|
||||
" return entity\n" +
|
||||
"end\n" );
|
||||
}
|
||||
|
||||
public void testSimpleRepeatUntil() {
|
||||
runFragment( LuaValue.valueOf(5),
|
||||
"local a\n"+
|
||||
"local w\n"+
|
||||
"repeat\n"+
|
||||
" a = w\n"+
|
||||
"until not a\n" +
|
||||
"return 5\n" );
|
||||
}
|
||||
|
||||
public void testTwoLoops() {
|
||||
runFragment( LuaValue.valueOf("b"),
|
||||
"local env = {}\n" +
|
||||
"for a,b in pairs(_G) do\n" +
|
||||
" c = function()\n" +
|
||||
" return b\n" +
|
||||
" end\n" +
|
||||
"end\n" +
|
||||
"local e = env\n" +
|
||||
"local f = {a='b'}\n" +
|
||||
"for k,v in pairs(f) do\n" +
|
||||
" return env[k] or v\n" +
|
||||
"end\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user