From 0348ac9f90ae57fe512c25a07c8c91790285c16a Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Fri, 6 Aug 2010 05:35:18 +0000 Subject: [PATCH] Refactor bytecode analysis --- src/jse/org/luaj/vm2/luajc/BasicBlock.java | 228 +++++++++ src/jse/org/luaj/vm2/luajc/JavaBuilder.java | 24 +- src/jse/org/luaj/vm2/luajc/JavaGen.java | 20 +- src/jse/org/luaj/vm2/luajc/JavaLoader.java | 2 +- src/jse/org/luaj/vm2/luajc/ProtoInfo.java | 317 ++++++++++++ src/jse/org/luaj/vm2/luajc/Slots.java | 536 -------------------- src/jse/org/luaj/vm2/luajc/UpvalInfo.java | 113 +++++ src/jse/org/luaj/vm2/luajc/VarInfo.java | 38 ++ 8 files changed, 723 insertions(+), 555 deletions(-) create mode 100644 src/jse/org/luaj/vm2/luajc/BasicBlock.java create mode 100644 src/jse/org/luaj/vm2/luajc/ProtoInfo.java delete mode 100644 src/jse/org/luaj/vm2/luajc/Slots.java create mode 100644 src/jse/org/luaj/vm2/luajc/UpvalInfo.java create mode 100644 src/jse/org/luaj/vm2/luajc/VarInfo.java diff --git a/src/jse/org/luaj/vm2/luajc/BasicBlock.java b/src/jse/org/luaj/vm2/luajc/BasicBlock.java new file mode 100644 index 00000000..ab2cbe05 --- /dev/null +++ b/src/jse/org/luaj/vm2/luajc/BasicBlock.java @@ -0,0 +1,228 @@ +/** + * + */ +package org.luaj.vm2.luajc; + +import java.util.Hashtable; +import java.util.Vector; + +import org.luaj.vm2.Lua; +import org.luaj.vm2.Prototype; + +public class BasicBlock { + int pc0,pc1; // range of program counter values for the block + BasicBlock[] prev; // previous basic blocks (0-n of these) + BasicBlock[] next; // next basic blocks (0, 1, or 2 of these) + + short[] ninputs; // number of input values per slot, >0 means is phi variable + VarInfo[][] inputs; // variables for each input, -1=closed/undefined, 1,2...=revisionof that variable + + public BasicBlock(Prototype p, int pc0) { + this.pc0 = this.pc1 = pc0; + this.ninputs = new short[p.maxstacksize]; + this.inputs = new VarInfo[p.maxstacksize][]; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append( (pc0+1)+"-"+(pc1+1) + +(prev!=null? " prv: "+str(prev,1): "") + +(next!=null? " nxt: "+str(next,0): "") + +"\n " ); + for ( int i=0; i 0 ) + sb.append( "," ); + sb.append( String.valueOf( p==1? b[i].pc1+1: b[i].pc0+1 ) ); + } + sb.append(")"); + return sb.toString(); + } + + public static BasicBlock[] findBasicBlocks(Prototype p) { + + // mark beginnings, endings + final int n = p.code.length; + final boolean[] isbeg = new boolean[n]; + final boolean[] isend = new boolean[n]; + isbeg[0] = true; + BranchVisitor bv = new BranchVisitor(isbeg) { + public void visitBranch(int pc0, int pc1) { + isend[pc0] = true; + isbeg[pc1] = true; + } + public void visitReturn(int pc) { + isend[pc] = true; + } + }; + visitBranches(p, bv); // 1st time to mark branches + visitBranches(p, bv); // 2nd time to catch merges + + // create basic blocks + final BasicBlock[] blocks = new BasicBlock[n]; + for ( int i=0; i inputs[slot].length ) { + VarInfo[] s = inputs[slot]; + inputs[slot] = new VarInfo[(n+1)*2]; + System.arraycopy(s, 0, inputs[slot], 0, n); + } + inputs[slot][n] = v; + ninputs[slot]++; + return true; + } + + boolean includesVar(int slot, VarInfo v) { + int n = ninputs[slot]; + for ( int i=0; i0? new ProtoInfo[p.p.length]: null; + + // find basic blocks + this.blocks = BasicBlock.findBasicBlocks(p); + this.blocklist = BasicBlock.sortDepthFirst(blocks); + + // find variables and block inputs + this.vars = findVariables(); + findBasicBlockInputs(); + + // find upvalues, create sub-prototypes + this.openups = new UpvalInfo[p.maxstacksize][]; + findUpvalues(); + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + + // prototpye name + sb.append( "proto '"+name+"'\n" ); + + // upvalues from outer scopes + for ( int i=0, n=(upvals!=null? upvals.length: 0); i0 && blocks[pc].pc0 != pc ) + for ( int j=0; j C) then R(A) := R(B) else pc++ */ + case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2); pc+=sBx */ + a = Lua.GETARG_A( ins ); + v[a][pc] = new VarInfo(a,pc); + break; + case Lua.OP_SELF: /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ + a = Lua.GETARG_A( ins ); + v[a][pc] = new VarInfo(a,pc); + v[a+1][pc] = new VarInfo(a+1,pc); + break; + case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2); + if R(A) =0; ) { + ++pc; + for ( int j=0; j0? new UpvalInfo[newp.nups]: null; + String newname = name + "$" + bx; + for ( int j=0; j C) then pc++ */ - s[a] |= BIT_REFER; - //branchdest[index+2] = true; - break; - - case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */ - s[a] |= BIT_REFER; - s[b] |= BIT_REFER; - //branchdest[index+2] = true; - break; - - case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */ - for ( int i=0; i0 ) - s[a++] |= BIT_REFER; - break; - - case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */ - s[a] |= BIT_REFER | BIT_ASSIGN; - s[a+2] |= BIT_REFER; - branchdest[index+1+sbx] = true; - break; - - case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) =) R(A)*/ - while ( a= slots.length ) - return false; - boolean hadchanges = false; - byte[] s = slots[src]; - byte[] d = slots[dest]; - for ( int j=0; j= p.code.length ) - return false; - int ins = p.code[index]; - switch ( Lua.GET_OPCODE(ins) ) { - case Lua.OP_LOADBOOL: - if ( Lua.GETARG_C(ins) == 0 ) - return true; - case Lua.OP_EQ: - case Lua.OP_LT: - case Lua.OP_LE: - case Lua.OP_TEST: - case Lua.OP_TESTSET: - case Lua.OP_TFORLOOP: - case Lua.OP_JMP: - case Lua.OP_FORPREP: - case Lua.OP_FORLOOP: - return true; - } - return false; - } - - private void markupvalues( ) { - for ( int pc=0; pc=0; ) { - int i = p.code[pc1]; - if ( Lua.GET_OPCODE(i) == Lua.OP_TFORLOOP ) { - int a = Lua.GETARG_A(i); - int c = Lua.GETARG_C(i); - for ( int pc0=pc1; --pc0>=0; ) { - i = p.code[pc0]; - int o = Lua.GET_OPCODE(i); - int sbx = Lua.GETARG_sBx(i); - if ( o == Lua.OP_JMP && (pc0 + 1 + sbx == pc1) ) { - for ( int j=1; j<=c; j++ ) { - checkPromoteLoopUpvalue( pc0+1, pc1+1, a+2+j ); - } - } - } - } - } - } - - private void checkPromoteLoopUpvalue(int index0, int index1, int slot) { - for ( int index=index0; index<=index1; ++index ) { - if ( (slots[index][slot] & BIT_UP_CREATE) != 0 ) { - for ( int i=index0+1; iassign) - promoteUpvalue( slots[index--], j ); - } - - private void promoteUpvalueAfter(int index, int j) { - int end = nextUndefined(index,j); - int access = lastAccessBefore(end,index,j); - while ( index<=access ) - promoteUpvalue( slots[index++], j ); - } - - private void promoteUpvalue(byte[] s, int slot) { - if ( (s[slot] & BIT_REFER) != 0 ) - s[slot] |= BIT_UP_REFER; - if ( (s[slot] & BIT_ASSIGN) != 0 ) - s[slot] |= BIT_UP_ASSIGN; - } - - private int prevUndefined(int index, int j) { - for ( ; index>=0; --index ) { - int s = slots[index][j]; - if ( ((s & BIT_INVALID) != 0) ) - return index; - else if ( ((s & BIT_NIL) != 0) ) - return index-1; - } - return index; - } - - private int firstBranchAfter(int index, int limit, int j) { - for ( ; ++index0 && this.branchdest[index-1] ) - return index; - return index; - } - - private int lastAssignBefore(int index, int limit, int j) { - for ( int i=index; i>limit; --i ) - if ( (slots[i][j] & (BIT_ASSIGN | BIT_NIL)) != 0 ) - return i; - return index; - } - - private int firstAssignAfter(int index, int limit, int j) { - for ( int i=index; ++ilimit; --index ) - if ( (slots[index][j] & (BIT_ASSIGN|BIT_REFER)) != 0 ) - return index; - return index; - } - - // ------------- pretty-print slot info -------------- - - String[] toStrings() { - int n = slots.length; - int m = slots[0].length; - String[] strs = new String[n]; - byte[] b = new byte[m+1]; - for ( int i=0; i0 ) ps.append( '\n' ); - ps.append( s[i] ); - if ( p != null && i>0 && i<=p.code.length ) - Print.printOpCode(ps, p, i-1); - } - ps.close(); - return baos.toString(); - } -} diff --git a/src/jse/org/luaj/vm2/luajc/UpvalInfo.java b/src/jse/org/luaj/vm2/luajc/UpvalInfo.java new file mode 100644 index 00000000..ebbfd25a --- /dev/null +++ b/src/jse/org/luaj/vm2/luajc/UpvalInfo.java @@ -0,0 +1,113 @@ +/** + * + */ +package org.luaj.vm2.luajc; + +public class UpvalInfo { + ProtoInfo pi; // where defined + int slot; // where defined + int nvars; // number of vars involved + VarInfo var[]; // list of vars + boolean rw; // read-write + + public UpvalInfo(ProtoInfo pi, int pc, int slot) { + this.pi = pi; + this.slot = slot; + this.nvars = 0; + this.var = null; + includeVars( pi.vars[slot][pc] ); + for ( int i=0; i 1; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append( pi.name ); + for ( int i=0; i0? ",": " " ); + sb.append( String.valueOf(var[i])); + } + if ( rw ) + sb.append( "(rw)" ); + return sb.toString(); + } + + private void includeVar(VarInfo v) { + if ( v == null ) + return; + if ( includes(v) ) + return; + if ( nvars == 0 ) { + var = new VarInfo[1]; + } else if ( nvars+1 >= var.length ) { + VarInfo[] s = var; + var = new VarInfo[nvars*2+1]; + System.arraycopy(s, 0, var, 0, nvars); + } + var[nvars++] = v; + } + + private boolean includes(VarInfo v) { + for ( int i=0; i b.pc0 ) + return pi.vars[slot][v.pc-1].upvalue != this; + if ( b.ninputs[slot] <= 0 ) + return true; + for ( int k=0, n=b.ninputs[slot]; k