diff --git a/src/jse/org/luaj/vm2/luajc/BasicBlock.java b/src/jse/org/luaj/vm2/luajc/BasicBlock.java index 8339039e..130f7947 100644 --- a/src/jse/org/luaj/vm2/luajc/BasicBlock.java +++ b/src/jse/org/luaj/vm2/luajc/BasicBlock.java @@ -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; @@ -150,36 +150,31 @@ public class BasicBlock { visitor.visitBranch( i, i+1 ); } } - - 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; i0 && b0.prev == null ) { - pc = b0.pc1; - continue; + for ( int bi=0; bi 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 3 - builder.newVarargs( pc, a+1, b-1 ); - narg = -1; + + 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 -1: // prev vararg result - loadVarargResults( builder, pc, a+1, vresultbase ); - narg = -1; + + case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */ + builder.loadConstant( p.k[bx] ); + builder.storeLocal( pc, a ); 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_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */ + builder.loadEnv(); + builder.loadConstant( p.k[bx] ); + builder.getTable(); + builder.storeLocal( pc, a ); break; - case 2: - if ( useinvoke ) - builder.arg( 1 ); + + 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) 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 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 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 { + + case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ + + // load function + builder.loadLocal(pc, a); + + // 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; - - 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) =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 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 ); + 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 { - 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 0 ) - builder.dup(); - builder.storeLocal( pc, a ); - if ( nup > 0 ) { - for ( int up=0; up=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 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; upb0.pc0 ) - for ( int j=0; j 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=) 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= 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; diff --git a/src/jse/org/luaj/vm2/luajc/VarInfo.java b/src/jse/org/luaj/vm2/luajc/VarInfo.java index bc449cc1..c2263ab6 100644 --- a/src/jse/org/luaj/vm2/luajc/VarInfo.java +++ b/src/jse/org/luaj/vm2/luajc/VarInfo.java @@ -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)) { diff --git a/test/junit/org/luaj/vm2/FragmentsTest.java b/test/junit/org/luaj/vm2/FragmentsTest.java index 4611834b..13374083 100644 --- a/test/junit/org/luaj/vm2/FragmentsTest.java +++ b/test/junit/org/luaj/vm2/FragmentsTest.java @@ -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"); + } } }