package test.javassist.bytecode.analysis;
import java.io.IOException;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.Bytecode;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.Opcode;
import javassist.bytecode.analysis.Subroutine;
import javassist.bytecode.analysis.SubroutineScanner;
import junit.framework.TestCase;
/**
* Tests Subroutine Scanner
*
* @author Jason T. Greene
*/
public class ScannerTest extends TestCase {
public void testNestedFinally() throws Exception {
ClassPool pool = ClassPool.getDefault();
generate(pool);
CtClass clazz = pool.get("test.ScannerTest$GeneratedTest");
CtMethod method = clazz.getDeclaredMethod("doit");
SubroutineScanner scanner = new SubroutineScanner();
Subroutine[] subs = scanner.scan(method.getMethodInfo2());
verifySubroutine(subs, 31, 31, new int[]{125, 25});
verifySubroutine(subs, 32, 31, new int[]{125, 25});
verifySubroutine(subs, 33, 31, new int[]{125, 25});
verifySubroutine(subs, 60, 31, new int[]{125, 25});
verifySubroutine(subs, 61, 31, new int[]{125, 25});
verifySubroutine(subs, 63, 31, new int[]{125, 25});
verifySubroutine(subs, 66, 31, new int[]{125, 25});
verifySubroutine(subs, 69, 31, new int[]{125, 25});
verifySubroutine(subs, 71, 31, new int[]{125, 25});
verifySubroutine(subs, 74, 31, new int[]{125, 25});
verifySubroutine(subs, 76, 31, new int[]{125, 25});
verifySubroutine(subs, 77, 77, new int[]{111, 71});
verifySubroutine(subs, 79, 77, new int[]{111, 71});
verifySubroutine(subs, 80, 77, new int[]{111, 71});
verifySubroutine(subs, 82, 77, new int[]{111, 71});
verifySubroutine(subs, 85, 77, new int[]{111, 71});
verifySubroutine(subs, 88, 77, new int[]{111, 71});
verifySubroutine(subs, 90, 77, new int[]{111, 71});
verifySubroutine(subs, 93, 77, new int[]{111, 71});
verifySubroutine(subs, 95, 77, new int[]{111, 71});
verifySubroutine(subs, 96, 96, new int[]{106, 90});
verifySubroutine(subs, 98, 96, new int[]{106, 90});
verifySubroutine(subs, 99, 96, new int[]{106, 90});
verifySubroutine(subs, 101, 96, new int[]{106, 90});
verifySubroutine(subs, 104, 96, new int[]{106, 90});
verifySubroutine(subs, 106, 77, new int[]{111, 71});
verifySubroutine(subs, 109, 77, new int[]{111, 71});
verifySubroutine(subs, 111, 31, new int[]{125, 25});
verifySubroutine(subs, 114, 31, new int[]{125, 25});
verifySubroutine(subs, 117, 31, new int[]{125, 25});
verifySubroutine(subs, 118, 31, new int[]{125, 25});
verifySubroutine(subs, 120, 31, new int[]{125, 25});
verifySubroutine(subs, 123, 31, new int[]{125, 25});
}
private static void verifySubroutine(Subroutine[] subs, int pos, int start,
int[] callers) {
Subroutine sub = subs[pos];
assertNotNull(sub);
assertEquals(sub.start(), start);
for (int i = 0; i < callers.length; i++)
assertTrue(sub.callers().contains(new Integer(callers[i])));
}
private static void generate(ClassPool pool) throws CannotCompileException, IOException, NotFoundException {
// Generated from eclipse JDK4 compiler:
// public void doit(int x) {
// println("null");
// try {
// println("try");
// } catch (RuntimeException e) {
// e.printStackTrace();
// } finally {
// switch (x) {
// default:
// case 15:
// try {
// println("inner-try");
// } finally {
// try {
// println("inner-inner-try");
// } finally {
// println("inner-finally");
// }
// }
// break;
// case 1789:
// println("switch -17");
// }
// }
//}
CtClass clazz = pool.makeClass("test.ScannerTest$GeneratedTest");
CtMethod method = new CtMethod(CtClass.voidType, "doit", new CtClass[] {CtClass.intType}, clazz);
MethodInfo info = method.getMethodInfo2();
info.setAccessFlags(AccessFlag.PUBLIC);
CtClass stringClass = pool.get("java.lang.String");
Bytecode code = new Bytecode(info.getConstPool(), 2, 9);
/* 0 */ code.addAload(0);
/* 1 */ code.addLdc("start");
/* 3 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
/* 6 */ code.addAload(0);
/* 7 */ code.addLdc("try");
/* 9 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
/* 12 */ addJump(code, Opcode.GOTO, 125);
/* 14 */ code.addAstore(2);
/* 16 */ code.addAload(2);
/* 17 */ code.addInvokevirtual("java.lang.Exception", "printStackTrace", "()V");
/* 20 */ addJump(code, Opcode.GOTO, 125);
/* 23 */ code.addAstore(4);
/* 25 */ addJump(code, Opcode.JSR, 31);
/* 28 */ code.addAload(4);
/* 30 */ code.addOpcode(Opcode.ATHROW);
/* 31 */ code.addAstore(3);
/* 32 */ code.addIload(1);
int spos = code.currentPc();
/* 33 */ code.addOpcode(Opcode.LOOKUPSWITCH);
code.addIndex(0); // 2 bytes pad - gets us to 36
code.add32bit(60 - spos); // default
code.add32bit(2); // 2 pairs
code.add32bit(15); code.add32bit(60 - spos);
code.add32bit(1789); code.add32bit(117 - spos);
/* 60 */ code.addAload(0);
/* 61 */ code.addLdc("inner-try");
/* 63 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
/* 66 */ addJump(code, Opcode.GOTO, 111);
/* 69 */ code.addAstore(6);
/* 71 */ addJump(code, Opcode.JSR, 77);
/* 74 */ code.addAload(6);
/* 76 */ code.add(Opcode.ATHROW);
/* 77 */ code.addAstore(5);
/* 79 */ code.addAload(0);
/* 80 */ code.addLdc("inner-inner-try");
/* 82 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
/* 85 */ addJump(code, Opcode.GOTO, 106);
/* 88 */ code.addAstore(8);
/* 90 */ addJump(code, Opcode.JSR, 96);
/* 93 */ code.addAload(8);
/* 95 */ code.add(Opcode.ATHROW);
/* 96 */ code.addAstore(7);
/* 98 */ code.addAload(0);
/* 99 */ code.addLdc("inner-finally");
/* 101 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
/* 104 */ code.addRet(7);
/* 106 */ addJump(code, Opcode.JSR, 96);
/* 109 */ code.addRet(5);
/* 111 */ addJump(code, Opcode.JSR, 77);
/* 114 */ addJump(code, Opcode.GOTO, 123);
/* 117 */ code.addAload(0);
/* 118 */ code.addLdc("switch - 1789");
/* 120 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
/* 123 */ code.addRet(3);
/* 125 */ addJump(code, Opcode.JSR, 31);
/* 128 */ code.addOpcode(Opcode.RETURN);
code.addExceptionHandler(6, 12, 15, "java.lang.RuntimeException");
code.addExceptionHandler(6, 20, 23, 0);
code.addExceptionHandler(125, 128, 23, 0);
code.addExceptionHandler(60, 69, 69, 0);
code.addExceptionHandler(111, 114, 69, 0);
code.addExceptionHandler(79, 88, 88, 0);
code.addExceptionHandler(106, 109, 88, 0);
info.setCodeAttribute(code.toCodeAttribute());
clazz.addMethod(method);
clazz.writeFile("/tmp");
}
private static void addJump(Bytecode code, int opcode, int pos) {
int current = code.currentPc();
code.addOpcode(opcode);
code.addIndex(pos - current);
}
}