Set up basic jit compiling framework.

This commit is contained in:
James Roseborough
2008-05-17 17:14:52 +00:00
parent 68d08c6cbd
commit 2f7f25e996
4 changed files with 499 additions and 1 deletions

View File

@@ -29,6 +29,9 @@ package org.luaj.vm;
public class LPrototype {
public LPrototype() {
}
public LClosure newClosure(LTable env) {
return new LClosure(this,env);
}
/* constants used by the function */
public LValue[] k;

View File

@@ -141,7 +141,7 @@ public class Print extends Lua {
}
}
static void printOpCode(LPrototype f, int pc) {
public static void printOpCode(LPrototype f, int pc) {
int[] code = f.code;
int i = code[pc];
int o = GET_OPCODE(i);

View File

@@ -0,0 +1,38 @@
package org.luaj.jit;
import org.luaj.vm.LClosure;
import org.luaj.vm.LPrototype;
import org.luaj.vm.LTable;
import org.luaj.vm.LuaState;
abstract
public class JitPrototype extends LPrototype {
protected LPrototype p;
public JitPrototype() {
super();
}
protected void setLuaPrototype(LPrototype lp) {
this.p = lp;
}
public LClosure newClosure(LTable env) {
return new JitClosure(this, env);
}
private static final class JitClosure extends LClosure {
private final JitPrototype jp;
public JitClosure(JitPrototype jitPrototype, LTable env) {
super( jitPrototype.p, env );
this.jp = jitPrototype;
}
public boolean luaStackCall(LuaState vm) {
jp.jitCall(vm,env);
return false;
}
}
public abstract void jitCall( LuaState vm, LTable env );
}

View File

@@ -0,0 +1,457 @@
package org.luaj.jit;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import org.luaj.compiler.LuaC;
import org.luaj.debug.Print;
import org.luaj.platform.J2sePlatform;
import org.luaj.vm.LClosure;
import org.luaj.vm.LPrototype;
import org.luaj.vm.LTable;
import org.luaj.vm.LValue;
import org.luaj.vm.Lua;
import org.luaj.vm.LuaState;
import org.luaj.vm.Platform;
public class LuaJit extends Lua {
public static void main(String[] args) throws IOException {
Platform.setInstance(new J2sePlatform());
LuaC.install();
String program = "print 'starting'\nfor i=1,10 do\n\tprint 'hello, world'\nend";
InputStream is = new ByteArrayInputStream(program.getBytes());
LPrototype p = LuaC.compile(is, "program");
test( p );
LPrototype q = LuaJit.compile( p );
test( q );
// JitPrototype jp = new JitPrototypeOne();
// jp.setLuaPrototype(p);
// test( jp );
}
private static void test(LPrototype p) {
try {
LuaState vm = Platform.newLuaState();
LClosure c = p.newClosure(vm._G);
vm.pushlvalue(c);
vm.call(0, 0);
} catch ( Throwable e ) {
e.printStackTrace();
}
}
public static LPrototype compile( LPrototype p ) {
int i, a, b, c, o, n, cb;
LValue rkb, rkc, nvarargs, key, val;
LValue i0, step, idx, limit, init, table;
boolean back, body;
PrintWriter pw = new PrintWriter( System.out );
String name = "JitPrototypeOne";
pw.print(
"package org.luaj.jit;\n"+
"import org.luaj.vm.LTable;\n"+
"import org.luaj.vm.LuaState;\n"+
"public class "+name+" extends JitPrototype {\n"+
" public void jitCall(LuaState vm, LTable env) {\n"+
"" );
int[] code = p.code;
LValue[] k = p.k;
// loop until a return instruction is processed,
// or the vm yields
for ( int pc=0; pc<code.length; pc++ ) {
// print the instruction
pw.print( "\n\t\t// ");
pw.flush();
Print.printOpCode(p, pc);
pw.println();
// get instruction
i = code[pc];
// get opcode and first arg
o = (i >> POS_OP) & MAX_OP;
a = (i >> POS_A) & MAXARG_A;
switch (o) {
case LuaState.OP_MOVE: {
b = LuaState.GETARG_B(i);
// this.stack[base + a] = this.stack[base + b];
pw.println( "\t\tvm.stack[base+"+a+"] = vm.stack[base+"+b+"];" );
continue;
}
case LuaState.OP_LOADK: {
b = LuaState.GETARG_Bx(i);
// this.stack[base + a] = k[b];
pw.println( "\t\tvm.stack[base+"+a+"] = p.k["+b+"];" );
continue;
}
/*
case LuaState.OP_LOADBOOL: {
b = LuaState.GETARG_B(i);
c = LuaState.GETARG_C(i);
this.stack[base + a] = (b != 0 ? LBoolean.TRUE : LBoolean.FALSE);
if (c != 0)
ci.pc++; // skip next instruction (if C)
continue;
}
case LuaState.OP_LOADNIL: {
b = LuaState.GETARG_B(i);
do {
this.stack[base + b] = LNil.NIL;
} while ((--b) >= a);
continue;
}
case LuaState.OP_GETUPVAL: {
b = LuaState.GETARG_B(i);
this.stack[base + a] = cl.upVals[b].getValue();
continue;
}
*/
case LuaState.OP_GETGLOBAL: {
b = LuaState.GETARG_Bx(i);
// key = k[b];
// table = cl.env;
// top = base + a;
// table.luaGetTable(this, table, key);
// pw.println("\t\tvm.top = base+"+a+";");
pw.println("\t\tvm.settop("+a+");");
pw.println("\t\tenv.luaGetTable(vm, env, p.k["+b+"]);");
continue;
}
/*
case LuaState.OP_GETTABLE: {
b = LuaState.GETARG_B(i);
key = GETARG_RKC(k, i);
table = this.stack[base + b];
top = base + a;
table.luaGetTable(this, table, key);
continue;
}
case LuaState.OP_SETGLOBAL: {
b = LuaState.GETARG_Bx(i);
key = k[b];
val = this.stack[base + a];
table = cl.env;
table.luaSetTable(this, table, key, val);
continue;
}
case LuaState.OP_SETUPVAL: {
b = LuaState.GETARG_B(i);
cl.upVals[b].setValue( this.stack[base + a] );
continue;
}
case LuaState.OP_SETTABLE: {
key = GETARG_RKB(k, i);
val = GETARG_RKC(k, i);
table = this.stack[base + a];
table.luaSetTable(this, table, key, val);
continue;
}
case LuaState.OP_NEWTABLE: {
b = LuaState.GETARG_B(i);
c = LuaState.GETARG_C(i);
this.stack[base + a] = new LTable(b, c);
continue;
}
case LuaState.OP_SELF: {
rkb = GETARG_RKB(k, i);
rkc = GETARG_RKC(k, i);
top = base + a;
rkb.luaGetTable(this, rkb, rkc);
this.stack[base + a + 1] = rkb;
// StkId rb = RB(i);
// setobjs2s(L, ra+1, rb);
// Protect(luaV_gettable(L, rb, RKC(i), ra));
continue;
}
case LuaState.OP_ADD:
case LuaState.OP_SUB:
case LuaState.OP_MUL:
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;
}
case LuaState.OP_UNM: {
rkb = GETARG_RKB(k, i);
this.stack[base + a] = rkb.luaUnaryMinus();
continue;
}
case LuaState.OP_NOT: {
rkb = GETARG_RKB(k, i);
this.stack[base + a] = (!rkb.toJavaBoolean() ? LBoolean.TRUE
: LBoolean.FALSE);
continue;
}
case LuaState.OP_LEN: {
rkb = GETARG_RKB(k, i);
this.stack[base + a] = LInteger.valueOf( rkb.luaLength() );
continue;
}
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;
}
case LuaState.OP_JMP: {
ci.pc += LuaState.GETARG_sBx(i);
continue;
}
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;
}
case LuaState.OP_TEST: {
c = LuaState.GETARG_C(i);
if (this.stack[base + a].toJavaBoolean() != (c != 0))
ci.pc++;
continue;
}
case LuaState.OP_TESTSET: {
rkb = GETARG_RKB(k, i);
c = LuaState.GETARG_C(i);
if (rkb.toJavaBoolean() != (c != 0))
ci.pc++;
else
this.stack[base + a] = rkb;
continue;
}
case LuaState.OP_CALL: {
// ra is base of new call frame
this.base += a;
// number of args
b = LuaState.GETARG_B(i);
if (b != 0) // else use previous instruction set top
top = base + b;
// number of return values we need
c = LuaState.GETARG_C(i);
// make or set up the call
this.nresults = c - 1;
if (this.stack[base].luaStackCall(this))
return;
// adjustTop only for case when call was completed
// and number of args > 0. If call completed but
// c == 0, leave top to point to end of results
if (c > 0)
adjustTop(base + c - 1);
// restore base
base = ci.base;
continue;
}
case LuaState.OP_TAILCALL: {
closeUpVals(base);
// copy down the frame before calling!
// number of args (including the function)
b = LuaState.GETARG_B(i);
if (b == 0)
b = top - (base + a);
// copy call + all args, discard current frame
System.arraycopy(stack, base + a, stack, ci.resultbase, b);
this.base = ci.resultbase;
this.top = base + b;
this.nresults = ci.nresults;
--cc;
// make or set up the call
try {
if (this.stack[base].luaStackCall(this)) {
return;
}
} catch (LuaErrorException e) {
// in case of lua error, we need to restore cc so that
// the debug can get the correct location where the error
// occured.
cc++;
throw e;
}
// adjustTop only for case when call was completed
// and number of args > 0. If call completed but
// c == 0, leave top to point to end of results
if (this.nresults >= 0)
adjustTop(base + nresults);
// force restore of base, etc.
return;
}
case LuaState.OP_RETURN: {
// number of return vals to return
b = LuaState.GETARG_B(i) - 1;
if (b == -1)
b = top - (base + a);
// close open upvals
closeUpVals( base );
// number to copy down
System.arraycopy(stack, base + a, stack, ci.resultbase, b);
top = ci.resultbase + b;
// adjust results to what caller expected
if (ci.nresults >= 0)
adjustTop(ci.resultbase + ci.nresults);
// pop the call stack
--cc;
// force a reload of the calling context
return;
}
case LuaState.OP_FORLOOP: {
i0 = this.stack[base + a];
step = this.stack[base + a + 2];
idx = step.luaBinOpUnknown(Lua.OP_ADD, i0);
limit = this.stack[base + a + 1];
back = step.luaBinCmpInteger(Lua.OP_LT, 0);
body = (back ? idx.luaBinCmpUnknown(Lua.OP_LE, limit) : limit
.luaBinCmpUnknown(Lua.OP_LE, idx));
if (body) {
this.stack[base + a] = idx;
this.stack[base + a + 3] = idx;
top = base + a + 3 + 1;
ci.pc += LuaState.GETARG_sBx(i);
}
continue;
}
case LuaState.OP_FORPREP: {
init = this.stack[base + a];
step = this.stack[base + a + 2];
this.stack[base + a] = step.luaBinOpUnknown(Lua.OP_SUB, init);
b = LuaState.GETARG_sBx(i);
ci.pc += b;
continue;
}
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;
}
case LuaState.OP_SETLIST: {
b = LuaState.GETARG_B(i);
c = LuaState.GETARG_C(i);
int listBase = base + a;
if (b == 0) {
b = top - listBase - 1;
}
if (c == 0) {
c = code[ci.pc++];
}
int offset = (c-1) * LFIELDS_PER_FLUSH;
LTable tbl = (LTable) this.stack[base + a];
for (int j=1; j<=b; j++) {
tbl.put(offset+j, stack[listBase + j]);
}
top = base + a - 1;
continue;
}
case LuaState.OP_CLOSE: {
closeUpVals( base + a ); // close upvals higher in the stack than position a
continue;
}
case LuaState.OP_CLOSURE: {
b = LuaState.GETARG_Bx(i);
proto = cl.p.p[b];
newClosure = new LClosure(proto, cl.env);
for (int j = 0; j < newClosure.upVals.length; j++, ci.pc++) {
i = code[ci.pc];
o = LuaState.GET_OPCODE(i);
b = LuaState.GETARG_B(i);
if (o == LuaState.OP_GETUPVAL) {
newClosure.upVals[j] = cl.upVals[b];
} else if (o == LuaState.OP_MOVE) {
newClosure.upVals[j] = findUpVal( base + b );
} else {
throw new java.lang.IllegalArgumentException(
"bad opcode: " + o);
}
}
this.stack[base + a] = newClosure;
continue;
}
case LuaState.OP_VARARG: {
// figure out how many args to copy
b = LuaState.GETARG_B(i) - 1;
nvarargs = this.stack[base - 1];
n = nvarargs.toJavaInt();
if (b == LuaState.LUA_MULTRET) {
b = n; // use entire varargs supplied
}
// copy args up to call stack area
checkstack(a+b);
for (int j = 0; j < b; j++)
this.stack[base + a + j] = (j < n ? this.stack[base
- n + j - 1]
: LNil.NIL);
top = base + a + b;
continue;
}
*/
}
}
pw.print( "\n"+
" return false;\n"+
" }\n"+
"}\n" );
pw.flush();
return p;
}
}