From eea19fa6f7e78fe4fa44bdec132106e1e3ad5476 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Mon, 9 Aug 2010 23:47:04 +0000 Subject: [PATCH] Improve bytecode generation. --- src/jse/org/luaj/vm2/luajc/ProtoInfo.java | 415 ++++++++++++++-------- src/jse/org/luaj/vm2/luajc/VarInfo.java | 115 ++++-- 2 files changed, 370 insertions(+), 160 deletions(-) diff --git a/src/jse/org/luaj/vm2/luajc/ProtoInfo.java b/src/jse/org/luaj/vm2/luajc/ProtoInfo.java index 1adf41c1..da70dd3d 100644 --- a/src/jse/org/luaj/vm2/luajc/ProtoInfo.java +++ b/src/jse/org/luaj/vm2/luajc/ProtoInfo.java @@ -3,9 +3,15 @@ package org.luaj.vm2.luajc; import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import org.luaj.vm2.Buffer; import org.luaj.vm2.Lua; +import org.luaj.vm2.LuaClosure; +import org.luaj.vm2.LuaTable; +import org.luaj.vm2.LuaValue; import org.luaj.vm2.Print; import org.luaj.vm2.Prototype; +import org.luaj.vm2.TailcallVarargs; +import org.luaj.vm2.UpValue; /** * Prototype information for static single-assignment analysis @@ -17,8 +23,8 @@ public class ProtoInfo { public final ProtoInfo[] subprotos; // one per enclosed prototype, or null public final BasicBlock[] blocks; // basic block analysis of code branching public final BasicBlock[] blocklist; // blocks in breadhth-first order - public final VarInfo[][] vars; // Each variable public final VarInfo[] params; // Parameters and initial values of stack variables + public final VarInfo[][] vars; // Each variable public final UpvalInfo[] upvals; // from outer scope public final UpvalInfo[][] openups; // per slot, upvalues allocated by this prototype @@ -46,9 +52,9 @@ public class ProtoInfo { this.blocklist[0].mergeSlotInput(slot, v); } - // find variables and block inputs + // find variables this.vars = findVariables(); - findBasicBlockInputs(); + replaceTrivialPhiVariables(); // find upvalues, create sub-prototypes this.openups = new UpvalInfo[p.maxstacksize][]; @@ -121,154 +127,275 @@ public class ProtoInfo { v[i] = new VarInfo[n]; // process instructions - for ( int pc=0; pc0 && 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; + // propogate previous for all but block boundaries + if ( pc>b0.pc0 ) for ( int j=0; j C) then R(A) := R(B) else pc++ */ + a = Lua.GETARG_A( ins ); + b = Lua.GETARG_B( ins ); + v[b][pc].isreferenced = true; + v[a][pc] = new VarInfo(a,pc); + 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) */ + a = Lua.GETARG_A( ins ); + b = Lua.GETARG_B( ins ); + c = Lua.GETARG_C( ins ); + if (!Lua.ISK(b)) v[b][pc].isreferenced = true; + if (!Lua.ISK(c)) v[c][pc].isreferenced = true; + v[a][pc] = new VarInfo(a,pc); + break; + + case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */ + a = Lua.GETARG_A( ins ); + b = Lua.GETARG_B( ins ); + c = Lua.GETARG_C( ins ); + v[a][pc].isreferenced = true; + if (!Lua.ISK(b)) v[b][pc].isreferenced = true; + if (!Lua.ISK(c)) v[c][pc].isreferenced = true; + break; + + case Lua.OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */ + a = Lua.GETARG_A( ins ); + b = Lua.GETARG_B( ins ); + c = Lua.GETARG_C( ins ); + for ( ; b<=c; b++ ) + v[b][pc].isreferenced = true; + v[a][pc] = new VarInfo(a,pc); + break; + + case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2); pc+=sBx */ + a = Lua.GETARG_A( ins ); + v[a+2][pc].isreferenced = true; + v[a][pc] = new VarInfo(a,pc); + break; + + case Lua.OP_GETTABLE: /* A B C R(A) := R(B)[RK(C)] */ + a = Lua.GETARG_A( ins ); + b = Lua.GETARG_B( ins ); + c = Lua.GETARG_C( ins ); + v[b][pc].isreferenced = true; + if (!Lua.ISK(c)) v[c][pc].isreferenced = true; + 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 ); + b = Lua.GETARG_B( ins ); + c = Lua.GETARG_C( ins ); + v[b][pc].isreferenced = true; + if (!Lua.ISK(c)) v[c][pc].isreferenced = true; + 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) =) R(A)*/ + a = Lua.GETARG_A( ins ); + for ( ; a C) then pc++ */ + a = Lua.GETARG_A( ins ); + v[a][pc].isreferenced = true; + 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++ */ + b = Lua.GETARG_B( ins ); + c = Lua.GETARG_C( ins ); + if (!Lua.ISK(b)) v[b][pc].isreferenced = true; + if (!Lua.ISK(c)) v[c][pc].isreferenced = true; + break; + + case Lua.OP_JMP: /* sBx pc+=sBx */ + break; + + default: + throw new IllegalStateException("unhandled opcode: "+ins); } - break; - case Lua.OP_CLOSE: - a = Lua.GETARG_A( ins ); - for ( ; a= 0 ) { + switch ( Lua.GET_OPCODE(prototype.code[pc]) ) { + case Lua.OP_CLOSURE: + case Lua.OP_CALL: + case Lua.OP_TFORLOOP: + pc -= 1; + break; + } + } VarInfo v = pc<0? params[slot]: vars[slot][pc]; // return v.upvalue != null && v.upvalue.rw; return v != null && v.upvalue != null; } public boolean isInitialValueUsed(int slot) { - return true; + VarInfo v = params[slot]; + return v.isreferenced; } } diff --git a/src/jse/org/luaj/vm2/luajc/VarInfo.java b/src/jse/org/luaj/vm2/luajc/VarInfo.java index 06078db9..bc449cc1 100644 --- a/src/jse/org/luaj/vm2/luajc/VarInfo.java +++ b/src/jse/org/luaj/vm2/luajc/VarInfo.java @@ -3,47 +3,120 @@ */ package org.luaj.vm2.luajc; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + public class VarInfo { - - public static VarInfo INVALID = new VarInfo(-1,-1); - + + public static VarInfo INVALID = new VarInfo(-1, -1); + public static VarInfo PARAM(int slot) { - return new VarInfo(slot,-1) { + return new VarInfo(slot, -1) { public String toString() { - return slot+".p"; + return slot + ".p"; } }; } - + public static VarInfo NIL(final int slot) { - return new VarInfo(slot,-1) { + return new VarInfo(slot, -1) { public String toString() { return "nil"; } }; } - public static VarInfo PHI(int slot, int pc) { - return new VarInfo(slot,pc) { - public String toString() { - return super.toString()+"{}"; - } - }; + public static VarInfo PHI(final ProtoInfo pi, final int slot, final int pc) { + return new PhiVarInfo(pi, slot, pc); } - + public final int slot; // where assigned - public final int pc; // where assigned, or -1 if for block inputs - - public UpvalInfo upvalue; // not null if this var is an upvalue - public boolean allocupvalue; // true if this variable allocates r/w upvalue storage - + public final int pc; // where assigned, or -1 if for block inputs + + public UpvalInfo upvalue; // not null if this var is an upvalue + public boolean allocupvalue; // true if this variable allocates r/w upvalue + // storage + public boolean isreferenced; // true if this variable is refenced by some + // opcode + public VarInfo(int slot, int pc) { this.slot = slot; this.pc = pc; } public String toString() { - return slot<0? "x.x": - (slot+"."+pc); + return slot < 0 ? "x.x" : (slot + "." + pc); + } + + /** Return replacement variable if there is exactly one value possible, + * otherwise compute entire collection of variables and return null. + * Computes the list of aall variable values, and saves it for the future. + * + * @return new Variable to replace with if there is only one value, or null to leave alone. + */ + public VarInfo resolvePhiVariableValues() { + return null; + } + + protected void collectUniqueValues(Set visitedBlocks, Set vars) { + vars.add(this); + } + + private static final class PhiVarInfo extends VarInfo { + private final ProtoInfo pi; + VarInfo[] values; + + private PhiVarInfo(ProtoInfo pi, int slot, int pc) { + super(slot, pc); + this.pi = pi; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append( super.toString() ); + sb.append("={"); + for (int i=0, n=(values!=null? values.length : 0); i0 ) + sb.append( "," ); + sb.append(String.valueOf(values[i])); + } + sb.append("}"); + return sb.toString(); + } + + public VarInfo resolvePhiVariableValues() { + Set visitedBlocks = new HashSet(); + Set vars = new HashSet(); + this.collectUniqueValues(visitedBlocks, vars); + if (vars.contains(INVALID)) + return INVALID; + int n = vars.size(); + Iterator it = vars.iterator(); + if (n == 1) { + VarInfo v = (VarInfo) it.next(); + v.isreferenced |= this.isreferenced; + return v; + } + this.values = new VarInfo[n]; + for ( int i=0; i