private String closureName(String classname, int subprotoindex) {
return classname+"$"+subprotoindex;
}
private void scanInstructions(ProtoInfo pi, String classname, JavaBuilder builder) {
Prototype p = pi.prototype;
int vresultbase = -1;
for ( int bi=0; bi<pi.blocklist.length; bi++ ) {
BasicBlock b0 = pi.blocklist[bi];
// convert upvalues that are phi-variables
for ( int slot=0; slot<p.maxstacksize; slot++ ) {
int pc = b0.pc0;
boolean c = pi.isUpvalueCreate(pc, slot);
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 ins = p.code[pc];
final int o = Lua.GET_OPCODE(ins);
int a = Lua.GETARG_A(ins);
int b = Lua.GETARG_B(ins);
int bx = Lua.GETARG_Bx(ins);
int sbx = Lua.GETARG_sBx(ins);
int c = Lua.GETARG_C(ins);
switch ( o ) {
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
builder.loadUpvalue( b );
builder.storeLocal( pc, a );
break;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
builder.storeUpvalue( pc, b, a );
break;
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
builder.newTable( b, c );
builder.storeLocal( pc, a );
break;
case Lua.OP_MOVE:/* A B R(A):= R(B) */
builder.loadLocal( pc, b );
builder.storeLocal( pc, a );
break;
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 Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
builder.loadConstant( p.k[bx] );
builder.storeLocal( pc, a );
break;
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 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;
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
for ( int k=b; k<=c; k++ )
builder.loadLocal(pc, k);
if ( c > b+1 ) {
builder.tobuffer();
for ( int k=c; --k>=b; )
builder.concatbuffer();
builder.tovalue();
} else {
builder.concatvalue();
}
builder.storeLocal(pc, a);
break;
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
builder.loadBoolean( b!=0 );
builder.storeLocal( pc, a );
if ( c!=0 )
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+2);
break;
case Lua.OP_JMP: /* sBx pc+=sBx */
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
break;
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.compareop(o);
builder.addBranch(pc, (a!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
break;
case Lua.OP_TEST: /* A C if not (R(A) <=> 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<b; i++ )
builder.loadLocal(pc, a+i);
break;
default: // fixed arg count > 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<c; i++ ) {
if ( i+1 < c )
builder.dup();
builder.arg( i );
builder.storeLocal(pc, a+i-1);
}
break;
case 0: // vararg result
vresultbase = a;
builder.storeVarresult();
break;
}
break;
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 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.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 {
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;
}
}
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) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
builder.loadLocal(pc, a);
builder.loadLocal(pc, a+2);
builder.binaryop( Lua.OP_ADD );
builder.dup();
builder.dup();
builder.storeLocal(pc, a);
builder.storeLocal(pc, a+3);
builder.loadLocal(pc, a+1); // limit
builder.loadLocal(pc, a+2); // step
builder.testForLoop();
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
break;
case Lua.OP_TFORLOOP: /*
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
* else pc++
*/
// v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
// if ( (o=v.arg1()).isnil() )
// ++pc;
builder.loadLocal(pc, a);
builder.loadLocal(pc, a+1);
builder.loadLocal(pc, a+2);
builder.invoke(2); // varresult on stack
builder.dup();
builder.storeVarresult();
builder.arg( 1 );
builder.isNil();
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+2);
// a[2] = a[3] = v[1], leave varargs on stack
builder.createUpvalues(pc, a+3, c);
builder.loadVarresult();
if (c>=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<c )
builder.dup();
builder.arg( j );
builder.storeLocal(pc, a+2+j);
}
break;
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1;
builder.loadLocal( pc, a );
if ( b == 0 ) {
int nstack = vresultbase - (a+1);
if ( nstack > 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();