diff --git a/src/script/org/luaj/jit/LuaJit.java b/src/script/org/luaj/jit/LuaJit.java index 29994a15..178ad242 100644 --- a/src/script/org/luaj/jit/LuaJit.java +++ b/src/script/org/luaj/jit/LuaJit.java @@ -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 TESTS = new HashSet(); + 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 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: { diff --git a/src/test/java/org/luaj/jit/LuaJitBasicTest.java b/src/test/java/org/luaj/jit/LuaJitBasicTest.java index 95a9215b..0dd2076a 100644 --- a/src/test/java/org/luaj/jit/LuaJitBasicTest.java +++ b/src/test/java/org/luaj/jit/LuaJitBasicTest.java @@ -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"); }