Fix jit flow control

This commit is contained in:
James Roseborough
2008-07-03 16:33:09 +00:00
parent f44de5cf17
commit e486c062f8
2 changed files with 90 additions and 109 deletions

View File

@@ -27,6 +27,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
@@ -118,15 +120,37 @@ public class LuaJit extends Lua implements LuaCompiler {
return RKBC_jit(GETARG_C(i));
}
private static boolean istest(int i) {
int o = Lua.GET_OPCODE(i);
return (o==OP_TEST);
private static Set<Integer> TESTS = new HashSet<Integer>();
static {
TESTS.add( OP_TEST );
TESTS.add( OP_EQ );
TESTS.add( OP_LT );
TESTS.add( OP_LE );
}
private static boolean isjump(int i) {
return Lua.GET_OPCODE(i) == OP_JMP;
private static boolean istest(int instr) {
int opcode = Lua.GET_OPCODE(instr);
return TESTS.contains(opcode);
}
private static boolean isjump(int instr) {
if ( OP_JMP != Lua.GET_OPCODE(instr) )
return false;
return true;
}
private static boolean isbackwardjump(int instr) {
return isjump(instr) && (LuaState.GETARG_sBx(instr) < 0);
}
private static boolean isforwardjump(int instr) {
return isjump(instr) && (LuaState.GETARG_sBx(instr) > 0);
}
private static boolean isloopbottom(int instr) {
return isbackwardjump(instr) || OP_FORLOOP == Lua.GET_OPCODE(instr);
}
private static String append( String s, String t ) {
return (s==null? t: t==null? s: s+t);
}
@@ -135,67 +159,68 @@ public class LuaJit extends Lua implements LuaCompiler {
if ( ! b )
throw new RuntimeException("assert failed");
}
private static String[] extractControlFlow( int[] code ) {
int n = code.length;
String[] s = new String[n];
int jmp,i2;
for ( int pc=0; pc<n; pc++ ) {
int i = code[pc];
switch ( Lua.GET_OPCODE(i) ) {
case OP_JMP:
jmp = LuaState.GETARG_sBx(i);
if ( jmp < 0 ) {
s[pc+jmp+1] = append( s[pc+jmp+1], "while (true) { /* WHILETOP */ " );
s[pc] = append( "} /* LOOPBOT */ ", s[pc] );
i2 = code[pc-1];
if ( istest(i2) ) {
s[pc] = append( "break; /* UNTIL */", s[pc] );
}
else if ( Lua.GET_OPCODE(i2) == OP_TFORLOOP ) {
int a = LuaState.GETARG_A(i2);
int c = LuaState.GETARG_C(i2);
assertTrue(c==2);
s[pc+jmp+1] = append( s[pc+jmp+1],
"\n\t\tvm.stack[base+"+(a+3)+"] = s"+(a+0)+";"+ // iterator
"\n\t\tvm.stack[base+"+(a+4)+"] = s"+(a+1)+";"+ // table
"\n\t\tvm.stack[base+"+(a+5)+"] = s"+(a+2)+";"+ // key
"\n\t\tvm.top = base+"+(a+6)+";"+
"\n\t\tvm.call(2,2);"+
"\n\t\ts"+(a+3)+" = vm.stack[base+"+(a+3)+"];"+ // next key
"\n\t\ts"+(a+4)+" = vm.stack[base+"+(a+4)+"];"+ // next value
"\n\t\tif ( s"+(a+3)+".isNil() )"+
"\n\t\t\tbreak;"+
"\n\t\ts"+(a+2)+" = s"+(a+3)+";" ); // save next key
}
break;
} else {
// forward jump to end of loop is a break
i2 = code[pc+jmp-1];
if ( Lua.GET_OPCODE(i2) == OP_JMP && LuaState.GETARG_sBx(i2) < 0 ) {
s[pc] = append( s[pc], "break " );
break;
}
// forward jump preceded by test is "if" block
if ( istest(code[pc-1]) ) {
s[pc] = append( s[pc], "{ /* IF */ " );
s[pc+jmp+1] = append( "} /* ENDIF */ ", s[pc+jmp+1] );
// end of block preceded by forward jump is else clause
i2 = code[pc+jmp];
int op2 = Lua.GET_OPCODE(i2);
int jmp2 = LuaState.GETARG_sBx(i2);
if ( op2 == OP_JMP && jmp2 > 0 ) {
s[pc+jmp+1] = append( s[pc+jmp+1], "else { /* ELSE */ " );
s[pc+jmp+jmp2+1] = append( "} /* ENDELSE */ ", s[pc+jmp+jmp2+1] );
}
}
// any backward jump is a loop bottom
if ( isbackwardjump(i) ) {
int jmp = LuaState.GETARG_sBx(i);
s[pc+jmp+1] = append( s[pc+jmp+1], "while (true) { /* WHILETOP */ " );
s[pc] = append( "} /* LOOPBOT */ ", s[pc] );
int i2 = code[pc-1];
if ( istest(i2) ) {
s[pc] = append( "break; /* UNTIL */", s[pc] );
}
// TFORLOOP test is at top in Java, not bottom
else if ( Lua.GET_OPCODE(i2) == OP_TFORLOOP ) {
int a = LuaState.GETARG_A(i2);
int c = LuaState.GETARG_C(i2);
assertTrue(c==2);
s[pc+jmp+1] = append( s[pc+jmp+1],
"\n\t\tvm.stack[base+"+(a+3)+"] = s"+(a+0)+";"+ // iterator
"\n\t\tvm.stack[base+"+(a+4)+"] = s"+(a+1)+";"+ // table
"\n\t\tvm.stack[base+"+(a+5)+"] = s"+(a+2)+";"+ // key
"\n\t\tvm.top = base+"+(a+6)+";"+
"\n\t\tvm.call(2,2);"+
"\n\t\ts"+(a+3)+" = vm.stack[base+"+(a+3)+"];"+ // next key
"\n\t\ts"+(a+4)+" = vm.stack[base+"+(a+4)+"];"+ // next value
"\n\t\tif ( s"+(a+3)+".isNil() )"+
"\n\t\t\tbreak;"+
"\n\t\ts"+(a+2)+" = s"+(a+3)+";" ); // save next key
}
break;
}
}
else if ( isforwardjump(i) ) {
// forward jump to loop bottom is a break
int jmp = LuaState.GETARG_sBx(i);
if ( isloopbottom(code[pc+jmp]) ) {
s[pc] = append( s[pc], "if(true)break;" );
}
// forward jump preceded by test is "if" block
else if ( istest(code[pc-1]) ) {
s[pc] = append( s[pc], "{ /* IF */ " );
s[pc+jmp+1] = append( "} /* ENDIF */ ", s[pc+jmp+1] );
// end of block preceded by forward jump is else clause
if ( isforwardjump(code[pc+jmp]) ) {
int jmp2 = LuaState.GETARG_sBx(code[pc+jmp]);
// unless that jump is a break!
if ( ! isloopbottom(code[pc+jmp+jmp2]) ) {
s[pc+jmp+1] = append( s[pc+jmp+1], "else { /* ELSE */ " );
s[pc+jmp+jmp2+1] = append( "} /* ENDELSE */ ", s[pc+jmp+jmp2+1] );
}
}
}
}
}
@@ -286,13 +311,11 @@ public class LuaJit extends Lua implements LuaCompiler {
break;
case LuaState.OP_MOVE: {
b = LuaState.GETARG_B(i);
// this.stack[base + a] = this.stack[base + b];
ps.println( "\t\ts"+a+" = s"+b+";" );
continue;
}
case LuaState.OP_LOADK: {
b = LuaState.GETARG_Bx(i);
// this.stack[base + a] = k[b];
ps.println( "\t\ts"+a+" = k"+b+";" );
continue;
}
@@ -367,10 +390,6 @@ public class LuaJit extends Lua implements LuaCompiler {
case LuaState.OP_DIV:
case LuaState.OP_MOD:
case LuaState.OP_POW: {
//rkb = GETARG_RKB(k, i);
//rkc = GETARG_RKC(k, i);
//this.stack[base + a] = rkc.luaBinOpUnknown(o, rkb);
//continue;
bs = GETARG_RKB_jit(i);
cs = GETARG_RKC_jit(i);
ps.println("\t\ts"+a+" = "+cs+".luaBinOpUnknown("+o+","+bs+");");
@@ -390,45 +409,27 @@ public class LuaJit extends Lua implements LuaCompiler {
ps.println("\t\ts"+a+" = LInteger.valueOf("+bs+".luaLength());");
}
case LuaState.OP_CONCAT: {
//b = LuaState.GETARG_B(i);
//c = LuaState.GETARG_C(i);
//int numValues = c - b + 1;
//ByteArrayOutputStream baos = new ByteArrayOutputStream();
//for (int j = b, l = 0; j <= c; j++, l++) {
// this.stack[base + j].luaConcatTo( baos );
//}
//this.stack[base + a] = new LString( baos.toByteArray() );
//continue;
b = LuaState.GETARG_B(i);
c = LuaState.GETARG_C(i);
ps.println("\t\tbaos = new ByteArrayOutputStream();");
for (int j = b; j <= c; j++)
ps.println("\t\ts"+j+".luaConcatTo( baos );");
ps.println("\t\ts"+a+" = new LString( baos.toByteArray() );");
ps.println("\t\tbaos = null;");
break;
}
case LuaState.OP_JMP: {
//ci.pc += LuaState.GETARG_sBx(i);
//continue;
break;
}
/*
case LuaState.OP_EQ:
case LuaState.OP_LT:
case LuaState.OP_LE: {
rkb = GETARG_RKB(k, i);
rkc = GETARG_RKC(k, i);
boolean test = rkc.luaBinCmpUnknown(o, rkb);
if (test == (a == 0))
ci.pc++;
continue;
bs = GETARG_RKB_jit(i);
cs = GETARG_RKC_jit(i);
ps.println( "\t\tif ( "+(a==0?"!":"")+" "+cs+".luaBinCmpUnknown("+o+", "+bs+") )" );
break;
}
*/
case LuaState.OP_TEST: {
//c = LuaState.GETARG_C(i);
//if (this.stack[base + a].toJavaBoolean() != (c != 0))
// ci.pc++;
//continue;
c = LuaState.GETARG_C(i);
ps.println( "\t\tif ( "+(c!=0?"!":"")+" s"+a+".toJavaBoolean() )" );
break;
@@ -596,26 +597,6 @@ public class LuaJit extends Lua implements LuaCompiler {
break;
}
case LuaState.OP_TFORLOOP: {
//cb = base + a + 3; // call base
//base = cb;
//adjustTop( cb + 3 );
//System.arraycopy(this.stack, cb-3, this.stack, cb, 3);
//
//// call the iterator
//c = LuaState.GETARG_C(i);
//this.nresults = c;
//if (this.stack[cb].luaStackCall(this))
// execute();
//base = ci.base;
//adjustTop( cb + c );
//
//// test for continuation
//if (!this.stack[cb].isNil() ) { // continue?
// this.stack[cb-1] = this.stack[cb]; // save control variable
//} else {
// ci.pc++; // skip over jump
//}
//continue;
break;
}
case LuaState.OP_SETLIST: {

View File

@@ -85,8 +85,8 @@ public class LuaJitBasicTest extends TestCase {
"local i=4\n" +
"while i>0 do\n"+
" print( i )\n"+
" break\n"+
" i = i-1\n"+
" break\n"+
"end\n");
}