169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage test.javassist.bytecode.analysis;
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.IOException;
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CannotCompileException;
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.ClassPool;
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtClass;
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtMethod;
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.NotFoundException;
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.AccessFlag;
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.Bytecode;
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.MethodInfo;
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.Opcode;
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.analysis.Subroutine;
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.analysis.SubroutineScanner;
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport junit.framework.TestCase;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Tests Subroutine Scanner
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Jason T. Greene
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class ScannerTest extends TestCase {
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void testNestedFinally() throws Exception {
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ClassPool pool = ClassPool.getDefault();
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        generate(pool);
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtClass clazz = pool.get("test.ScannerTest$GeneratedTest");
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtMethod method = clazz.getDeclaredMethod("doit");
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        SubroutineScanner scanner = new SubroutineScanner();
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Subroutine[] subs = scanner.scan(method.getMethodInfo2());
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 31, 31, new int[]{125, 25});
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 32, 31, new int[]{125, 25});
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 33, 31, new int[]{125, 25});
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 60, 31, new int[]{125, 25});
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 61, 31, new int[]{125, 25});
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 63, 31, new int[]{125, 25});
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 66, 31, new int[]{125, 25});
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 69, 31, new int[]{125, 25});
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 71, 31, new int[]{125, 25});
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 74, 31, new int[]{125, 25});
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 76, 31, new int[]{125, 25});
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 77, 77, new int[]{111, 71});
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 79, 77, new int[]{111, 71});
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 80, 77, new int[]{111, 71});
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 82, 77, new int[]{111, 71});
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 85, 77, new int[]{111, 71});
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 88, 77, new int[]{111, 71});
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 90, 77, new int[]{111, 71});
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 93, 77, new int[]{111, 71});
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 95, 77, new int[]{111, 71});
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 96, 96, new int[]{106, 90});
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 98, 96, new int[]{106, 90});
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 99, 96, new int[]{106, 90});
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 101, 96, new int[]{106, 90});
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 104, 96, new int[]{106, 90});
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 106, 77, new int[]{111, 71});
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 109, 77, new int[]{111, 71});
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 111, 31, new int[]{125, 25});
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 114, 31, new int[]{125, 25});
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 117, 31, new int[]{125, 25});
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 118, 31, new int[]{125, 25});
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 120, 31, new int[]{125, 25});
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        verifySubroutine(subs, 123, 31, new int[]{125, 25});
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void verifySubroutine(Subroutine[] subs, int pos, int start,
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int[] callers) {
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Subroutine sub = subs[pos];
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        assertNotNull(sub);
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        assertEquals(sub.start(), start);
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < callers.length; i++)
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            assertTrue(sub.callers().contains(new Integer(callers[i])));
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void generate(ClassPool pool) throws CannotCompileException, IOException, NotFoundException {
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // Generated from eclipse JDK4 compiler:
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // public void doit(int x) {
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //    println("null");
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //    try {
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        println("try");
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //    } catch (RuntimeException e) {
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        e.printStackTrace();
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //    } finally {
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        switch (x) {
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        default:
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        case 15:
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        try {
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //            println("inner-try");
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        } finally {
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //            try {
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //                println("inner-inner-try");
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //            } finally {
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //                println("inner-finally");
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //            }
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        }
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        break;
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        case 1789:
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        println("switch -17");
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //        }
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //    }
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //}
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtClass clazz = pool.makeClass("test.ScannerTest$GeneratedTest");
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtMethod method = new CtMethod(CtClass.voidType, "doit", new CtClass[] {CtClass.intType}, clazz);
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo info = method.getMethodInfo2();
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        info.setAccessFlags(AccessFlag.PUBLIC);
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtClass stringClass = pool.get("java.lang.String");
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Bytecode code = new Bytecode(info.getConstPool(), 2, 9);
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 0   */ code.addAload(0);
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 1   */ code.addLdc("start");
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 3   */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 6   */ code.addAload(0);
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 7   */ code.addLdc("try");
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 9   */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 12  */ addJump(code, Opcode.GOTO, 125);
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 14  */ code.addAstore(2);
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 16  */ code.addAload(2);
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 17  */ code.addInvokevirtual("java.lang.Exception", "printStackTrace", "()V");
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 20  */ addJump(code, Opcode.GOTO, 125);
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 23  */ code.addAstore(4);
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 25  */ addJump(code, Opcode.JSR, 31);
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 28  */ code.addAload(4);
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 30  */ code.addOpcode(Opcode.ATHROW);
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 31  */ code.addAstore(3);
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 32  */ code.addIload(1);
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int spos = code.currentPc();
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 33  */ code.addOpcode(Opcode.LOOKUPSWITCH);
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                  code.addIndex(0); // 2 bytes pad - gets us to 36
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                  code.add32bit(60 - spos); // default
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                  code.add32bit(2); // 2 pairs
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                  code.add32bit(15); code.add32bit(60 - spos);
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                  code.add32bit(1789); code.add32bit(117 - spos);
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 60  */ code.addAload(0);
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 61  */ code.addLdc("inner-try");
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 63  */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 66  */ addJump(code, Opcode.GOTO, 111);
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 69  */ code.addAstore(6);
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 71  */ addJump(code, Opcode.JSR, 77);
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 74  */ code.addAload(6);
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 76  */ code.add(Opcode.ATHROW);
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 77  */ code.addAstore(5);
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 79  */ code.addAload(0);
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 80  */ code.addLdc("inner-inner-try");
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 82  */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 85  */ addJump(code, Opcode.GOTO, 106);
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 88  */ code.addAstore(8);
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 90  */ addJump(code, Opcode.JSR, 96);
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 93  */ code.addAload(8);
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 95  */ code.add(Opcode.ATHROW);
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 96  */ code.addAstore(7);
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 98  */ code.addAload(0);
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 99  */ code.addLdc("inner-finally");
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 101 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 104 */ code.addRet(7);
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 106 */ addJump(code, Opcode.JSR, 96);
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 109 */ code.addRet(5);
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 111 */ addJump(code, Opcode.JSR, 77);
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 114 */ addJump(code, Opcode.GOTO, 123);
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 117 */ code.addAload(0);
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 118 */ code.addLdc("switch - 1789");
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 120 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 123 */ code.addRet(3);
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 125 */ addJump(code, Opcode.JSR, 31);
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /* 128 */ code.addOpcode(Opcode.RETURN);
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addExceptionHandler(6, 12, 15, "java.lang.RuntimeException");
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addExceptionHandler(6, 20, 23, 0);
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addExceptionHandler(125, 128, 23, 0);
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addExceptionHandler(60, 69, 69, 0);
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addExceptionHandler(111, 114, 69, 0);
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addExceptionHandler(79, 88, 88, 0);
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addExceptionHandler(106, 109, 88, 0);
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        info.setCodeAttribute(code.toCodeAttribute());
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        clazz.addMethod(method);
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        clazz.writeFile("/tmp");
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void addJump(Bytecode code, int opcode, int pos) {
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int current = code.currentPc();
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addOpcode(opcode);
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addIndex(pos - current);
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
186