diff options
author | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2007-04-26 14:58:17 +0000 |
---|---|---|
committer | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2007-04-26 14:58:17 +0000 |
commit | 1012230ca3a9d5b5e0f66cb56246f7fc255f881e (patch) | |
tree | b4c76b2bb0787097af1d7954e36034cbad778704 /src/main/javassist/bytecode/stackmap/MapMaker.java | |
parent | 10c21b809410d9c2b164bf5d88ec12a9787e4590 (diff) | |
download | javassist-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.java | 269 |
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 { |