aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/bytecode/stackmap/MapMaker.java
diff options
context:
space:
mode:
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2007-04-26 14:58:17 +0000
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2007-04-26 14:58:17 +0000
commit1012230ca3a9d5b5e0f66cb56246f7fc255f881e (patch)
treeb4c76b2bb0787097af1d7954e36034cbad778704 /src/main/javassist/bytecode/stackmap/MapMaker.java
parent10c21b809410d9c2b164bf5d88ec12a9787e4590 (diff)
downloadjavassist-1012230ca3a9d5b5e0f66cb56246f7fc255f881e.tar.gz
javassist-1012230ca3a9d5b5e0f66cb56246f7fc255f881e.zip
snapshot. I am still working on stackmap support.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@360 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main/javassist/bytecode/stackmap/MapMaker.java')
-rw-r--r--src/main/javassist/bytecode/stackmap/MapMaker.java269
1 files changed, 200 insertions, 69 deletions
diff --git a/src/main/javassist/bytecode/stackmap/MapMaker.java b/src/main/javassist/bytecode/stackmap/MapMaker.java
index c7e92c04..cbb238c9 100644
--- a/src/main/javassist/bytecode/stackmap/MapMaker.java
+++ b/src/main/javassist/bytecode/stackmap/MapMaker.java
@@ -22,23 +22,34 @@ import javassist.bytecode.*;
* Stack map maker.
*/
public class MapMaker extends Tracer {
- private boolean moveon;
+ private boolean moveon; // used for returning another value from doOpcode().
+ private boolean loopDetected;
+ private int iteration;
private BasicBlock[] blocks;
public static void main(String[] args) throws Exception {
- if (args.length > 1) {
+ boolean useMain2 = args[0].equals("0");
+ if (useMain2 && args.length > 1) {
main2(args);
return;
}
+ for (int i = 0; i < args.length; i++)
+ main1(args[i]);
+ }
+
+ public static void main1(String className) throws Exception {
ClassPool cp = ClassPool.getDefault();
- javassist.CtClass cc = cp.get(args[0]);
+ //javassist.CtClass cc = cp.get(className);
+ javassist.CtClass cc = cp.makeClass(new java.io.FileInputStream(className));
+ System.out.println(className);
ClassFile cf = cc.getClassFile();
java.util.List minfos = cf.getMethods();
for (int i = 0; i < minfos.size(); i++) {
MethodInfo minfo = (MethodInfo)minfos.get(i);
CodeAttribute ca = minfo.getCodeAttribute();
- ca.setAttribute(MapMaker.getMap(cp, minfo));
+ if (ca != null)
+ ca.setAttribute(MapMaker.getMap(cp, minfo));
}
cc.writeFile("tmp");
@@ -46,19 +57,25 @@ public class MapMaker extends Tracer {
public static void main2(String[] args) throws Exception {
ClassPool cp = ClassPool.getDefault();
- javassist.CtClass cc = cp.get(args[0]);
+ //javassist.CtClass cc = cp.get(args[1]);
+ javassist.CtClass cc = cp.makeClass(new java.io.FileInputStream(args[1]));
+ MethodInfo minfo;
MapMaker mm;
- if (args[1].equals("_init_"))
- mm = makeMapMaker(cp, cc.getDeclaredConstructors()[0].getMethodInfo());
+ if (args[2].equals("_init_"))
+ // minfo = cc.getDeclaredConstructors()[0].getMethodInfo();
+ minfo = cc.getClassInitializer().getMethodInfo();
else
- mm = makeMapMaker(cp, cc.getDeclaredMethod(args[1]).getMethodInfo());
+ minfo = cc.getDeclaredMethod(args[2]).getMethodInfo();
+ mm = makeMapMaker(cp, minfo);
if (mm == null)
System.out.println("single basic block");
else {
BasicBlock[] blocks = mm.getBlocks();
for (int i = 0; i < blocks.length; i++)
System.out.println(blocks[i]);
+
+ StackMapTable smt = mm.toStackMap();
}
}
@@ -77,21 +94,26 @@ public class MapMaker extends Tracer {
return mm.toStackMap();
}
- /*
+ /**
* Makes basic blocks with stack maps. If the number of the basic blocks
- * is one, this method returns null.
+ * is one, this method returns null. If the given method info does not
+ * include a code attribute, this method also returns null.
*/
public static MapMaker makeMapMaker(ClassPool classes, MethodInfo minfo)
throws BadBytecode
{
CodeAttribute ca = minfo.getCodeAttribute();
+ if (ca == null)
+ return null;
+
CodeIterator ci = ca.iterator();
ConstPool pool = minfo.getConstPool();
ExceptionTable et = ca.getExceptionTable();
BasicBlock[] blocks = BasicBlock.makeBlocks(ci, 0, ci.getCodeLength(),
et, 0, pool);
if (blocks.length < 2)
- return null;
+ if (blocks.length == 0 || blocks[0].inbound < 1)
+ return null;
boolean isStatic = (minfo.getAccessFlags() & AccessFlag.STATIC) != 0;
int maxStack = ca.getMaxStack();
@@ -102,7 +124,7 @@ public class MapMaker extends Tracer {
isStatic, minfo.isConstructor());
String retType = BasicBlock.getRetType(desc);
MapMaker mm = new MapMaker(classes, pool, maxStack, maxLocals,
- blocks, retType, blocks[0]);
+ blocks, retType, blocks[0], 0);
mm.make(ca.getCode(), et);
return mm;
}
@@ -111,19 +133,22 @@ public class MapMaker extends Tracer {
* Constructs a tracer.
*/
MapMaker(ClassPool classes, ConstPool cp,
- int maxStack, int maxLocals, BasicBlock[] bb,
- String retType, BasicBlock init) {
- this(classes, cp, maxStack, maxLocals, bb, retType);
+ int maxStack, int maxLocals, BasicBlock[] bb,
+ String retType, BasicBlock init, int iterate)
+ {
+ this(classes, cp, maxStack, maxLocals, bb, retType, iterate);
TypeData[] srcTypes = init.localsTypes;
copyFrom(srcTypes.length, srcTypes, this.localsTypes);
}
private MapMaker(ClassPool classes, ConstPool cp,
int maxStack, int maxLocals, BasicBlock[] bb,
- String retType)
+ String retType, int iterateNo)
{
super(classes, cp, maxStack, maxLocals, retType);
blocks = bb;
+ loopDetected = false;
+ iteration = iterateNo;
}
public BasicBlock[] getBlocks() { return blocks; }
@@ -132,41 +157,18 @@ public class MapMaker extends Tracer {
* Runs an analyzer.
*/
void make(byte[] code, ExceptionTable et) throws BadBytecode {
+ blocks[0].version = iteration;
make(code, blocks[0]);
- traceExceptions(code, et);
+ if (loopDetected) {
+ blocks[0].version = ++iteration;
+ make(code, blocks[0]);
+ }
+
int n = blocks.length;
for (int i = 0; i < n; i++)
evalExpected(blocks[i]);
}
- private void traceExceptions(byte[] code, ExceptionTable et)
- throws BadBytecode
- {
- int n = et.size();
- for (int i = 0; i < n; i++) {
- int startPc = et.startPc(i);
- int handlerPc = et.handlerPc(i);
- BasicBlock handler = BasicBlock.find(blocks, handlerPc);
- if (handler.alreadySet())
- continue;
-
- BasicBlock thrower = BasicBlock.find(blocks, startPc);
- TypeData[] srcTypes = thrower.localsTypes;
- copyFrom(srcTypes.length, srcTypes, this.localsTypes);
- int typeIndex = et.catchType(i);
- String type;
- if (typeIndex == 0)
- type = "java.lang.Throwable";
- else
- type = cpool.getClassInfo(typeIndex);
-
- stackTop = 1;
- stackTypes[0] = new TypeData.ClassName(type);
- recordStackMap(handler);
- make(code, handler);
- }
- }
-
// Phase 1: Code Tracing
private void make(byte[] code, BasicBlock bb)
@@ -174,6 +176,7 @@ public class MapMaker extends Tracer {
{
int pos = bb.position;
int end = pos + bb.length;
+ traceExceptions(code, bb.catchBlocks);
moveon = true;
while (moveon && pos < end)
pos += doOpcode(pos, code);
@@ -186,16 +189,55 @@ public class MapMaker extends Tracer {
private void nextBlock(int pos, byte[] code, int offset) throws BadBytecode {
BasicBlock bb = BasicBlock.find(blocks, pos + offset);
- if (bb.alreadySet()) {
+ if (bb.alreadySet(iteration)) {
mergeMap(stackTypes, bb.stackTypes);
mergeMap(localsTypes, bb.localsTypes);
+ mergeUsage(bb);
}
else {
recordStackMap(bb);
+ bb.version = iteration;
MapMaker maker = new MapMaker(classPool, cpool, stackTypes.length,
- localsTypes.length, blocks, returnType);
+ localsTypes.length, blocks, returnType, iteration);
maker.copyFrom(this);
maker.make(code, bb);
+ recordUsage(bb, maker);
+ if (maker.loopDetected)
+ this.loopDetected = true;
+ }
+ }
+
+ private void traceExceptions(byte[] code, BasicBlock.Branch branches)
+ throws BadBytecode
+ {
+ while (branches != null) {
+ int pos = branches.target;
+ BasicBlock bb = BasicBlock.find(blocks, pos);
+ if (bb.alreadySet(iteration)) {
+ mergeMap(localsTypes, bb.localsTypes);
+ mergeUsage(bb);
+ }
+ else {
+ recordStackMap(bb, branches.typeIndex);
+ bb.version = iteration;
+ MapMaker maker = new MapMaker(classPool, cpool, stackTypes.length,
+ localsTypes.length, blocks, returnType, iteration);
+
+ /* the following code is equivalent to maker.copyFrom(this)
+ * except stackTypes are not copied.
+ */
+ maker.stackTypes[0] = bb.stackTypes[0].getSelf();
+ maker.stackTop = 1;
+ TypeData[] srcTypes = this.localsTypes;
+ copyFrom(srcTypes.length, srcTypes, maker.localsTypes);
+
+ maker.make(code, bb);
+ recordUsage(bb, maker);
+ if (maker.loopDetected)
+ this.loopDetected = true;
+ }
+
+ branches = branches.next;
}
}
@@ -234,7 +276,10 @@ public class MapMaker extends Tracer {
TypeData t = srcTypes[i];
destTypes[i] = t == null ? null : t.getSelf();
if (t != TOP)
- k = i;
+ if (t.is2WordType())
+ k = i + 1;
+ else
+ k = i;
}
return k + 1;
@@ -255,13 +300,65 @@ public class MapMaker extends Tracer {
target.setStackMap(st, tStackTypes, k, tLocalsTypes);
}
+ private void recordStackMap(BasicBlock target, int exceptionType)
+ throws BadBytecode
+ {
+ int n = localsTypes.length;
+ TypeData[] tLocalsTypes = new TypeData[n];
+ int k = copyFrom(n, localsTypes, tLocalsTypes);
+
+ String type;
+ if (exceptionType == 0)
+ type = "java.lang.Throwable";
+ else
+ type = cpool.getClassInfo(exceptionType);
+
+ TypeData[] tStackTypes = new TypeData[stackTypes.length];
+ tStackTypes[0] = new TypeData.ClassName(type);
+
+ target.setStackMap(1, tStackTypes, k, tLocalsTypes);
+ }
+
+ private void recordUsage(BasicBlock target, MapMaker next) {
+ int[] nextUsage = next.localsUsage;
+ TypeData[] tData = target.localsTypes;
+ int n = tData.length;
+ for (int i = blocks[0].numLocals; i < n; i++)
+ if (nextUsage[i] == READ)
+ readLocal(i);
+ else
+ tData[i] = TOP;
+
+ int[] usage = new int[nextUsage.length];
+ n = usage.length;
+ for (int i = 0; i < n; i++)
+ usage[i] = nextUsage[i];
+
+ target.localsUsage = usage;
+ }
+
+ private void mergeUsage(BasicBlock target) {
+ int[] usage = target.localsUsage;
+ if (usage == null) {
+ // detected a loop.
+ loopDetected = true;
+ }
+ else {
+ int n = usage.length;
+ for (int i = 0; i < n; i++)
+ if (usage[i] == READ)
+ readLocal(i);
+ }
+ }
+
// Phase 2
void evalExpected(BasicBlock target) throws BadBytecode {
ClassPool cp = classPool;
evalExpected(cp, target.stackTop, target.stackTypes);
TypeData[] types = target.localsTypes;
- evalExpected(cp, types.length, types);
+ if (types != null) // unless this block is dead code
+ evalExpected(cp, types.length, types);
}
private static void evalExpected(ClassPool cp, int n, TypeData[] types)
@@ -282,13 +379,18 @@ public class MapMaker extends Tracer {
int n = blocks.length;
BasicBlock prev = blocks[0];
int offsetDelta = prev.length;
+ if (prev.inbound > 0) { // the first instruction is a branch target.
+ writer.sameFrame(0);
+ offsetDelta--;
+ }
+
for (int i = 1; i < n; i++) {
BasicBlock bb = blocks[i];
if (bb.inbound > 0) {
bb.resetNumLocals();
int diffL = stackMapDiff(prev.numLocals, prev.localsTypes,
bb.numLocals, bb.localsTypes);
- toStackMapBody(writer, bb, diffL, offsetDelta);
+ toStackMapBody(writer, bb, diffL, offsetDelta, prev);
offsetDelta = bb.length - 1;
prev = bb;
}
@@ -301,7 +403,7 @@ public class MapMaker extends Tracer {
}
private void toStackMapBody(StackMapTable.Writer writer, BasicBlock bb,
- int diffL, int offsetDelta) {
+ int diffL, int offsetDelta, BasicBlock prev) {
// if diffL is -100, two TypeData arrays do not share
// any elements.
@@ -316,17 +418,16 @@ public class MapMaker extends Tracer {
return;
}
else if (0 < diffL && diffL <= 3) {
- int[] tags = new int[diffL];
int[] data = new int[diffL];
- fillStackMap(diffL, bb.numLocals - diffL, tags, data,
- bb.localsTypes);
+ int[] tags = fillStackMap(bb.numLocals - prev.numLocals,
+ prev.numLocals, data,
+ bb.localsTypes);
writer.appendFrame(offsetDelta, tags, data);
return;
}
}
else if (stackTop == 1 && diffL == 0) {
- TypeData[] types = bb.stackTypes;
- TypeData td = types[0];
+ TypeData td = bb.stackTypes[0];
if (td == TOP)
writer.sameLocals(offsetDelta, StackMapTable.TOP, 0);
else
@@ -334,30 +435,45 @@ public class MapMaker extends Tracer {
td.getTypeData(cpool));
return;
}
+ else if (stackTop == 2 && diffL == 0) {
+ TypeData td = bb.stackTypes[0];
+ if (td != TOP && td.is2WordType()) {
+ // bb.stackTypes[1] must be TOP.
+ writer.sameLocals(offsetDelta, td.getTypeTag(),
+ td.getTypeData(cpool));
+ return;
+ }
+ }
- int[] stags = new int[stackTop];
int[] sdata = new int[stackTop];
- int nl = bb.numLocals;
- int[] ltags = new int[nl];
- int[] ldata = new int[nl];
- fillStackMap(stackTop, 0, stags, sdata, bb.stackTypes);
- fillStackMap(nl, 0, ltags, ldata, bb.localsTypes);
+ int[] stags = fillStackMap(stackTop, 0, sdata, bb.stackTypes);
+ int[] ldata = new int[bb.numLocals];
+ int[] ltags = fillStackMap(bb.numLocals, 0, ldata, bb.localsTypes);
writer.fullFrame(offsetDelta, ltags, ldata, stags, sdata);
}
- private void fillStackMap(int num, int offset, int[] tags, int[] data, TypeData[] types) {
+ private int[] fillStackMap(int num, int offset, int[] data, TypeData[] types) {
+ int realNum = diffSize(types, offset, offset + num);
ConstPool cp = cpool;
+ int[] tags = new int[realNum];
+ int j = 0;
for (int i = 0; i < num; i++) {
TypeData td = types[offset + i];
if (td == TOP) {
- tags[i] = StackMapTable.TOP;
- data[i] = 0;
+ tags[j] = StackMapTable.TOP;
+ data[j] = 0;
}
else {
- tags[i] = td.getTypeTag();
- data[i] = td.getTypeData(cp);
+ tags[j] = td.getTypeTag();
+ data[j] = td.getTypeData(cp);
+ if (td.is2WordType())
+ i++;
}
+
+ j++;
}
+
+ return tags;
}
private static int stackMapDiff(int oldTdLen, TypeData[] oldTd,
@@ -371,7 +487,10 @@ public class MapMaker extends Tracer {
len = newTdLen;
if (stackMapEq(oldTd, newTd, len))
- return diff;
+ if (diff > 0)
+ return diffSize(newTd, len, newTdLen);
+ else
+ return -diffSize(oldTd, len, oldTdLen);
else
return -100;
}
@@ -379,7 +498,7 @@ public class MapMaker extends Tracer {
private static boolean stackMapEq(TypeData[] oldTd, TypeData[] newTd, int len) {
for (int i = 0; i < len; i++) {
TypeData td = oldTd[i];
- if (td == TOP) {
+ if (td == TOP) { // the next element to LONG/DOUBLE is TOP.
if (newTd[i] != TOP)
return false;
}
@@ -391,6 +510,18 @@ public class MapMaker extends Tracer {
return true;
}
+ private static int diffSize(TypeData[] types, int offset, int len) {
+ int num = 0;
+ while (offset < len) {
+ TypeData td = types[offset++];
+ num++;
+ if (td != TOP && td.is2WordType())
+ offset++;
+ }
+
+ return num;
+ }
+
// Branch actions
protected void visitBranch(int pos, byte[] code, int offset) throws BadBytecode {