1package test.javassist.bytecode.analysis; 2 3import java.io.IOException; 4 5import javassist.CannotCompileException; 6import javassist.ClassPool; 7import javassist.CtClass; 8import javassist.CtMethod; 9import javassist.NotFoundException; 10import javassist.bytecode.AccessFlag; 11import javassist.bytecode.Bytecode; 12import javassist.bytecode.MethodInfo; 13import javassist.bytecode.Opcode; 14import javassist.bytecode.analysis.Subroutine; 15import javassist.bytecode.analysis.SubroutineScanner; 16import junit.framework.TestCase; 17 18/** 19 * Tests Subroutine Scanner 20 * 21 * @author Jason T. Greene 22 */ 23public class ScannerTest extends TestCase { 24 25 public void testNestedFinally() throws Exception { 26 ClassPool pool = ClassPool.getDefault(); 27 generate(pool); 28 CtClass clazz = pool.get("test.ScannerTest$GeneratedTest"); 29 CtMethod method = clazz.getDeclaredMethod("doit"); 30 31 SubroutineScanner scanner = new SubroutineScanner(); 32 Subroutine[] subs = scanner.scan(method.getMethodInfo2()); 33 34 verifySubroutine(subs, 31, 31, new int[]{125, 25}); 35 verifySubroutine(subs, 32, 31, new int[]{125, 25}); 36 verifySubroutine(subs, 33, 31, new int[]{125, 25}); 37 verifySubroutine(subs, 60, 31, new int[]{125, 25}); 38 verifySubroutine(subs, 61, 31, new int[]{125, 25}); 39 verifySubroutine(subs, 63, 31, new int[]{125, 25}); 40 verifySubroutine(subs, 66, 31, new int[]{125, 25}); 41 verifySubroutine(subs, 69, 31, new int[]{125, 25}); 42 verifySubroutine(subs, 71, 31, new int[]{125, 25}); 43 verifySubroutine(subs, 74, 31, new int[]{125, 25}); 44 verifySubroutine(subs, 76, 31, new int[]{125, 25}); 45 verifySubroutine(subs, 77, 77, new int[]{111, 71}); 46 verifySubroutine(subs, 79, 77, new int[]{111, 71}); 47 verifySubroutine(subs, 80, 77, new int[]{111, 71}); 48 verifySubroutine(subs, 82, 77, new int[]{111, 71}); 49 verifySubroutine(subs, 85, 77, new int[]{111, 71}); 50 verifySubroutine(subs, 88, 77, new int[]{111, 71}); 51 verifySubroutine(subs, 90, 77, new int[]{111, 71}); 52 verifySubroutine(subs, 93, 77, new int[]{111, 71}); 53 verifySubroutine(subs, 95, 77, new int[]{111, 71}); 54 verifySubroutine(subs, 96, 96, new int[]{106, 90}); 55 verifySubroutine(subs, 98, 96, new int[]{106, 90}); 56 verifySubroutine(subs, 99, 96, new int[]{106, 90}); 57 verifySubroutine(subs, 101, 96, new int[]{106, 90}); 58 verifySubroutine(subs, 104, 96, new int[]{106, 90}); 59 verifySubroutine(subs, 106, 77, new int[]{111, 71}); 60 verifySubroutine(subs, 109, 77, new int[]{111, 71}); 61 verifySubroutine(subs, 111, 31, new int[]{125, 25}); 62 verifySubroutine(subs, 114, 31, new int[]{125, 25}); 63 verifySubroutine(subs, 117, 31, new int[]{125, 25}); 64 verifySubroutine(subs, 118, 31, new int[]{125, 25}); 65 verifySubroutine(subs, 120, 31, new int[]{125, 25}); 66 verifySubroutine(subs, 123, 31, new int[]{125, 25}); 67 } 68 69 private static void verifySubroutine(Subroutine[] subs, int pos, int start, 70 int[] callers) { 71 Subroutine sub = subs[pos]; 72 assertNotNull(sub); 73 assertEquals(sub.start(), start); 74 for (int i = 0; i < callers.length; i++) 75 assertTrue(sub.callers().contains(new Integer(callers[i]))); 76 } 77 78 private static void generate(ClassPool pool) throws CannotCompileException, IOException, NotFoundException { 79 // Generated from eclipse JDK4 compiler: 80 // public void doit(int x) { 81 // println("null"); 82 // try { 83 // println("try"); 84 // } catch (RuntimeException e) { 85 // e.printStackTrace(); 86 // } finally { 87 // switch (x) { 88 // default: 89 // case 15: 90 // try { 91 // println("inner-try"); 92 // } finally { 93 // try { 94 // println("inner-inner-try"); 95 // } finally { 96 // println("inner-finally"); 97 // } 98 // } 99 // break; 100 // case 1789: 101 // println("switch -17"); 102 // } 103 // } 104 //} 105 106 CtClass clazz = pool.makeClass("test.ScannerTest$GeneratedTest"); 107 CtMethod method = new CtMethod(CtClass.voidType, "doit", new CtClass[] {CtClass.intType}, clazz); 108 MethodInfo info = method.getMethodInfo2(); 109 info.setAccessFlags(AccessFlag.PUBLIC); 110 CtClass stringClass = pool.get("java.lang.String"); 111 Bytecode code = new Bytecode(info.getConstPool(), 2, 9); 112 /* 0 */ code.addAload(0); 113 /* 1 */ code.addLdc("start"); 114 /* 3 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass}); 115 /* 6 */ code.addAload(0); 116 /* 7 */ code.addLdc("try"); 117 /* 9 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass}); 118 /* 12 */ addJump(code, Opcode.GOTO, 125); 119 /* 14 */ code.addAstore(2); 120 /* 16 */ code.addAload(2); 121 /* 17 */ code.addInvokevirtual("java.lang.Exception", "printStackTrace", "()V"); 122 /* 20 */ addJump(code, Opcode.GOTO, 125); 123 /* 23 */ code.addAstore(4); 124 /* 25 */ addJump(code, Opcode.JSR, 31); 125 /* 28 */ code.addAload(4); 126 /* 30 */ code.addOpcode(Opcode.ATHROW); 127 /* 31 */ code.addAstore(3); 128 /* 32 */ code.addIload(1); 129 int spos = code.currentPc(); 130 /* 33 */ code.addOpcode(Opcode.LOOKUPSWITCH); 131 code.addIndex(0); // 2 bytes pad - gets us to 36 132 code.add32bit(60 - spos); // default 133 code.add32bit(2); // 2 pairs 134 code.add32bit(15); code.add32bit(60 - spos); 135 code.add32bit(1789); code.add32bit(117 - spos); 136 /* 60 */ code.addAload(0); 137 /* 61 */ code.addLdc("inner-try"); 138 /* 63 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass}); 139 /* 66 */ addJump(code, Opcode.GOTO, 111); 140 /* 69 */ code.addAstore(6); 141 /* 71 */ addJump(code, Opcode.JSR, 77); 142 /* 74 */ code.addAload(6); 143 /* 76 */ code.add(Opcode.ATHROW); 144 /* 77 */ code.addAstore(5); 145 /* 79 */ code.addAload(0); 146 /* 80 */ code.addLdc("inner-inner-try"); 147 /* 82 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass}); 148 /* 85 */ addJump(code, Opcode.GOTO, 106); 149 /* 88 */ code.addAstore(8); 150 /* 90 */ addJump(code, Opcode.JSR, 96); 151 /* 93 */ code.addAload(8); 152 /* 95 */ code.add(Opcode.ATHROW); 153 /* 96 */ code.addAstore(7); 154 /* 98 */ code.addAload(0); 155 /* 99 */ code.addLdc("inner-finally"); 156 /* 101 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass}); 157 /* 104 */ code.addRet(7); 158 /* 106 */ addJump(code, Opcode.JSR, 96); 159 /* 109 */ code.addRet(5); 160 /* 111 */ addJump(code, Opcode.JSR, 77); 161 /* 114 */ addJump(code, Opcode.GOTO, 123); 162 /* 117 */ code.addAload(0); 163 /* 118 */ code.addLdc("switch - 1789"); 164 /* 120 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass}); 165 /* 123 */ code.addRet(3); 166 /* 125 */ addJump(code, Opcode.JSR, 31); 167 /* 128 */ code.addOpcode(Opcode.RETURN); 168 code.addExceptionHandler(6, 12, 15, "java.lang.RuntimeException"); 169 code.addExceptionHandler(6, 20, 23, 0); 170 code.addExceptionHandler(125, 128, 23, 0); 171 code.addExceptionHandler(60, 69, 69, 0); 172 code.addExceptionHandler(111, 114, 69, 0); 173 code.addExceptionHandler(79, 88, 88, 0); 174 code.addExceptionHandler(106, 109, 88, 0); 175 info.setCodeAttribute(code.toCodeAttribute()); 176 clazz.addMethod(method); 177 clazz.writeFile("/tmp"); 178 } 179 180 private static void addJump(Bytecode code, int opcode, int pos) { 181 int current = code.currentPc(); 182 code.addOpcode(opcode); 183 code.addIndex(pos - current); 184 } 185} 186