Improve bytecode generation.

This commit is contained in:
James Roseborough
2010-08-12 00:49:15 +00:00
parent 267e89adef
commit 386e89aedf
5 changed files with 446 additions and 410 deletions

View File

@@ -3,7 +3,6 @@
*/ */
package org.luaj.vm2.luajc; package org.luaj.vm2.luajc;
import java.util.Hashtable;
import java.util.Vector; import java.util.Vector;
import org.luaj.vm2.Lua; import org.luaj.vm2.Lua;
@@ -13,6 +12,7 @@ public class BasicBlock {
int pc0,pc1; // range of program counter values for the block int pc0,pc1; // range of program counter values for the block
BasicBlock[] prev; // previous basic blocks (0-n of these) BasicBlock[] prev; // previous basic blocks (0-n of these)
BasicBlock[] next; // next basic blocks (0, 1, or 2 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) { public BasicBlock(Prototype p, int pc0) {
this.pc0 = this.pc1 = pc0; this.pc0 = this.pc1 = pc0;
@@ -151,35 +151,30 @@ public class BasicBlock {
} }
} }
public static BasicBlock[] sortDepthFirst(BasicBlock[] blocks) { public static BasicBlock[] findLiveBlocks(BasicBlock[] blocks) {
Vector list = new Vector(); // add reachable blocks
Hashtable seen = new Hashtable(); Vector next = new Vector ();
Vector next = new Vector();
BasicBlock b0,b1,b[];
next.addElement( blocks[0] ); next.addElement( blocks[0] );
seen.put( blocks[0], Boolean.TRUE ); while ( ! next.isEmpty() ) {
while ( (b = toBasicBlockArray(next)) != null ) { BasicBlock b = (BasicBlock) next.elementAt(0);
next.clear(); next.removeElementAt(0);
for ( int i=0; i<b.length; i++ ) { if ( ! b.islive ) {
list.addElement( b0 = b[i] ); b.islive = true;
for ( int k=0, n=b0.next!=null? b0.next.length: 0; k<n; k++ ) { for ( int i=0, n=b.next!=null? b.next.length: 0; i<n; i++ )
if ( seen.get( b1 = b0.next[k] ) == null ) { if ( ! b.next[i].islive )
seen.put( b1, Boolean.TRUE ); next.addElement( b.next[i] );
next.addElement( b1 );
} }
} }
}
}
return toBasicBlockArray(list);
}
private static BasicBlock[] toBasicBlockArray(Vector list) { // create list in natural order
if ( list.size() <= 0 ) Vector list = new Vector();
return null; 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()]; BasicBlock[] array = new BasicBlock[list.size()];
list.copyInto(array); list.copyInto(array);
return array; return array;
} }
} }

View File

@@ -66,15 +66,19 @@ public class JavaGen {
Prototype p = pi.prototype; Prototype p = pi.prototype;
int vresultbase = -1; 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 // convert upvalues that are phi-variables
BasicBlock b0 = pi.blocks[pc]; for ( int slot=0; slot<p.maxstacksize; slot++ ) {
if ( b0.pc0>0 && b0.prev == null ) { int pc = b0.pc0;
pc = b0.pc1; boolean c = pi.isUpvalueCreate(pc, slot);
continue; if ( c && pi.vars[slot][pc].isPhiVar() )
builder.convertToUpvalue(pc, slot);
} }
for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) {
int pc0 = pc; // closure changes pc int pc0 = pc; // closure changes pc
int ins = p.code[pc]; int ins = p.code[pc];
final int o = Lua.GET_OPCODE(ins); final int o = Lua.GET_OPCODE(ins);
@@ -391,28 +395,6 @@ public class JavaGen {
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
{ {
/*
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 );
} 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]; Prototype newp = p.p[bx];
String protoname = closureName(classname, bx); String protoname = closureName(classname, bx);
int nup = newp.nups; int nup = newp.nups;
@@ -434,7 +416,6 @@ public class JavaGen {
} }
pc += nup; pc += nup;
} }
//*/
break; break;
} }
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
@@ -455,6 +436,7 @@ public class JavaGen {
builder.onEndOfLuaInstruction( pc0 ); builder.onEndOfLuaInstruction( pc0 );
} }
} }
}
private void loadVarargResults(JavaBuilder builder, int pc, int a, int vresultbase) { private void loadVarargResults(JavaBuilder builder, int pc, int a, int vresultbase) {
if ( vresultbase <= a ) { if ( vresultbase <= a ) {

View File

@@ -22,7 +22,6 @@ public class ProtoInfo {
public final UpvalInfo[] upvals; // from outer scope public final UpvalInfo[] upvals; // from outer scope
public final UpvalInfo[][] openups; // per slot, upvalues allocated by this prototype public final UpvalInfo[][] openups; // per slot, upvalues allocated by this prototype
public ProtoInfo(Prototype p, String name) { public ProtoInfo(Prototype p, String name) {
this(p,name,null); this(p,name,null);
} }
@@ -35,8 +34,7 @@ public class ProtoInfo {
// find basic blocks // find basic blocks
this.blocks = BasicBlock.findBasicBlocks(p); this.blocks = BasicBlock.findBasicBlocks(p);
this.blocklist = BasicBlock.sortDepthFirst(blocks); this.blocklist = BasicBlock.findLiveBlocks(blocks);
// params are inputs to first block // params are inputs to first block
this.params = new VarInfo[p.maxstacksize]; this.params = new VarInfo[p.maxstacksize];
@@ -65,8 +63,9 @@ public class ProtoInfo {
sb.append( " up["+i+"]: "+upvals[i]+"\n" ); sb.append( " up["+i+"]: "+upvals[i]+"\n" );
// basic blocks // basic blocks
for ( int pc0=blocks[0].pc0; pc0<prototype.code.length; pc0=blocks[pc0].pc1+1 ) { for ( int i=0; i<blocklist.length; i++ ) {
BasicBlock b = blocks[pc0]; BasicBlock b = blocklist[i];
int pc0 = b.pc0;
sb.append( " block "+b.toString() ); sb.append( " block "+b.toString() );
appendOpenUps( sb, -1 ); appendOpenUps( sb, -1 );
@@ -143,19 +142,18 @@ public class ProtoInfo {
if ( v[slot][bp.pc1] == VarInfo.INVALID ) if ( v[slot][bp.pc1] == VarInfo.INVALID )
var = VarInfo.INVALID; var = VarInfo.INVALID;
} }
}
if ( var == null ) if ( var == null )
var = VarInfo.PHI(this, slot, b0.pc0); var = VarInfo.PHI(this, slot, b0.pc0);
}
v[slot][b0.pc0] = var; v[slot][b0.pc0] = var;
} }
// process instructions for this basic block // process instructions for this basic block
for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) { for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) {
// propogate previous for all but block boundaries // propogate previous values except at block boundaries
if ( pc>b0.pc0 ) if ( pc > b0.pc0 )
for ( int j=0; j<m; j++ ) propogateVars( v, pc-1, pc );
v[j][pc] = v[j][pc-1];
int a,b,c,nups; int a,b,c,nups;
int ins = prototype.code[pc]; int ins = prototype.code[pc];
@@ -322,10 +320,8 @@ public class ProtoInfo {
} }
} }
v[a][pc] = new VarInfo(a,pc); v[a][pc] = new VarInfo(a,pc);
for ( int k=1; k<=nups; ++k ) { for ( int k=1; k<=nups; k++ )
for ( int j=0; j<m; j++ ) propogateVars( v, pc, pc+k );
v[j][pc+k] = v[j][pc];
}
pc += nups; pc += nups;
break; break;
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/ case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
@@ -369,11 +365,16 @@ public class ProtoInfo {
return v; 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() { private void replaceTrivialPhiVariables() {
for ( int i=0; i<blocklist.length; i++ ) { for ( int i=0; i<blocklist.length; i++ ) {
BasicBlock b0 = blocklist[i]; BasicBlock b0 = blocklist[i];
for ( int slot=0; slot<prototype.maxstacksize; slot++ ) { for ( int slot=0; slot<prototype.maxstacksize; slot++ ) {
VarInfo vold = vars[slot][b0.pc1]; VarInfo vold = vars[slot][b0.pc0];
VarInfo vnew = vold.resolvePhiVariableValues(); VarInfo vnew = vold.resolvePhiVariableValues();
if ( vnew != null ) if ( vnew != null )
substituteVariable( slot, vold, vnew ); substituteVariable( slot, vold, vnew );
@@ -443,7 +444,7 @@ public class ProtoInfo {
public boolean isUpvalueRefer(int pc, int slot) { public boolean isUpvalueRefer(int pc, int slot) {
// special case when both refer and assign in same instruction // 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; pc -= 1;
VarInfo v = pc<0? params[slot]: vars[slot][pc]; VarInfo v = pc<0? params[slot]: vars[slot][pc];
return v != null && v.upvalue != null && v.upvalue.rw; return v != null && v.upvalue != null && v.upvalue.rw;

View File

@@ -63,6 +63,10 @@ public class VarInfo {
vars.add(this); vars.add(this);
} }
public boolean isPhiVar() {
return false;
}
private static final class PhiVarInfo extends VarInfo { private static final class PhiVarInfo extends VarInfo {
private final ProtoInfo pi; private final ProtoInfo pi;
VarInfo[] values; VarInfo[] values;
@@ -72,6 +76,10 @@ public class VarInfo {
this.pi = pi; this.pi = pi;
} }
public boolean isPhiVar() {
return true;
}
public String toString() { public String toString() {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
sb.append( super.toString() ); sb.append( super.toString() );
@@ -108,6 +116,8 @@ public class VarInfo {
protected void collectUniqueValues(Set visitedBlocks, Set vars) { protected void collectUniqueValues(Set visitedBlocks, Set vars) {
BasicBlock b = pi.blocks[pc]; 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++) { for (int i = 0, n = b.prev != null ? b.prev.length : 0; i < n; i++) {
BasicBlock bp = b.prev[i]; BasicBlock bp = b.prev[i];
if (!visitedBlocks.contains(bp)) { if (!visitedBlocks.contains(bp)) {

View File

@@ -501,5 +501,53 @@ public class FragmentsTest extends TestSuite {
" return c,b,a\n" + " return c,b,a\n" +
"end\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");
}
} }
} }