0001: /***
0002: * ASM tests
0003: * Copyright (c) 2002-2005 France Telecom
0004: * All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: * 1. Redistributions of source code must retain the above copyright
0010: * notice, this list of conditions and the following disclaimer.
0011: * 2. Redistributions in binary form must reproduce the above copyright
0012: * notice, this list of conditions and the following disclaimer in the
0013: * documentation and/or other materials provided with the distribution.
0014: * 3. Neither the name of the copyright holders nor the names of its
0015: * contributors may be used to endorse or promote products derived from
0016: * this software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
0028: * THE POSSIBILITY OF SUCH DAMAGE.
0029: */package org.objectweb.asm.commons;
0030:
0031: import junit.framework.TestCase;
0032:
0033: import org.objectweb.asm.ClassWriter;
0034: import org.objectweb.asm.Label;
0035: import org.objectweb.asm.MethodVisitor;
0036: import org.objectweb.asm.Opcodes;
0037: import org.objectweb.asm.tree.MethodNode;
0038: import org.objectweb.asm.util.TraceMethodVisitor;
0039:
0040: /**
0041: * JsrInlinerTest
0042: *
0043: * @author Eugene Kuleshov, Niko Matsakis, Eric Bruneton
0044: */
0045: public class JSRInlinerAdapterUnitTest extends TestCase {
0046:
0047: private JSRInlinerAdapter jsr;
0048: private MethodNode exp;
0049: private MethodVisitor current;
0050:
0051: protected void setUp() throws Exception {
0052: super .setUp();
0053: jsr = new JSRInlinerAdapter(null, 0, "m", "()V", null, null) {
0054: public void visitEnd() {
0055: System.err.println("started w/ method:" + name);
0056: TraceMethodVisitor mv = new TraceMethodVisitor();
0057: for (int i = 0; i < instructions.size(); ++i) {
0058: instructions.get(i).accept(mv);
0059: System.err.print(Integer.toString(i + 100000)
0060: .substring(1));
0061: System.err.print(" : " + mv.text.get(i));
0062: }
0063: super .visitEnd();
0064: System.err.println("finished w/ method:" + name);
0065: }
0066: };
0067: exp = new MethodNode(0, "m", "()V", null, null);
0068: }
0069:
0070: private void setCurrent(final MethodVisitor cv) {
0071: this .current = cv;
0072: }
0073:
0074: private void ICONST_0() {
0075: this .current.visitInsn(Opcodes.ICONST_0);
0076: }
0077:
0078: private void ISTORE(final int var) {
0079: this .current.visitVarInsn(Opcodes.ISTORE, var);
0080: }
0081:
0082: private void ALOAD(final int var) {
0083: this .current.visitVarInsn(Opcodes.ALOAD, var);
0084: }
0085:
0086: private void ILOAD(final int var) {
0087: this .current.visitVarInsn(Opcodes.ILOAD, var);
0088: }
0089:
0090: private void ASTORE(final int var) {
0091: this .current.visitVarInsn(Opcodes.ASTORE, var);
0092: }
0093:
0094: private void RET(final int var) {
0095: this .current.visitVarInsn(Opcodes.RET, var);
0096: }
0097:
0098: private void ATHROW() {
0099: this .current.visitInsn(Opcodes.ATHROW);
0100: }
0101:
0102: private void ACONST_NULL() {
0103: this .current.visitInsn(Opcodes.ACONST_NULL);
0104: }
0105:
0106: private void RETURN() {
0107: this .current.visitInsn(Opcodes.RETURN);
0108: }
0109:
0110: private void LABEL(final Label l) {
0111: this .current.visitLabel(l);
0112: }
0113:
0114: private void IINC(final int var, final int amnt) {
0115: this .current.visitIincInsn(var, amnt);
0116: }
0117:
0118: private void GOTO(final Label l) {
0119: this .current.visitJumpInsn(Opcodes.GOTO, l);
0120: }
0121:
0122: private void JSR(final Label l) {
0123: this .current.visitJumpInsn(Opcodes.JSR, l);
0124: }
0125:
0126: private void IFNONNULL(final Label l) {
0127: this .current.visitJumpInsn(Opcodes.IFNONNULL, l);
0128: }
0129:
0130: private void IFNE(final Label l) {
0131: this .current.visitJumpInsn(Opcodes.IFNE, l);
0132: }
0133:
0134: private void TRYCATCH(final Label start, final Label end,
0135: final Label handler) {
0136: this .current.visitTryCatchBlock(start, end, handler, null);
0137: }
0138:
0139: private void LINE(final int line, final Label start) {
0140: this .current.visitLineNumber(line, start);
0141: }
0142:
0143: private void LOCALVAR(final String name, final String desc,
0144: final int index, final Label start, final Label end) {
0145: this .current.visitLocalVariable(name, desc, null, start, end,
0146: index);
0147: }
0148:
0149: private void END(final int maxStack, final int maxLocals) {
0150: this .current.visitMaxs(maxStack, maxLocals);
0151: this .current.visitEnd();
0152: ClassWriter cw = new ClassWriter(0);
0153: cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "C", null,
0154: "java/lang/Object", null);
0155: MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
0156: "()V", null, null);
0157: mv.visitCode();
0158: mv.visitVarInsn(Opcodes.ALOAD, 0);
0159: mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object",
0160: "<init>", "()V");
0161: mv.visitInsn(Opcodes.RETURN);
0162: mv.visitMaxs(1, 1);
0163: mv.visitEnd();
0164: ((MethodNode) this .current).accept(cw);
0165: cw.visitEnd();
0166: byte[] b = cw.toByteArray();
0167: try {
0168: TestClassLoader loader = new TestClassLoader();
0169: Class c = loader.defineClass("C", b);
0170: c.newInstance();
0171: } catch (Throwable t) {
0172: fail(t.getMessage());
0173: }
0174: this .current = null;
0175: }
0176:
0177: static class TestClassLoader extends ClassLoader {
0178:
0179: public Class defineClass(final String name, final byte[] b) {
0180: return defineClass(name, b, 0, b.length);
0181: }
0182: }
0183:
0184: /**
0185: * Tests a method which has the most basic <code>try{}finally</code> form
0186: * imaginable:
0187: *
0188: * <pre>
0189: * public void a() {
0190: * int a = 0;
0191: * try {
0192: * a++;
0193: * } finally {
0194: * a--;
0195: * }
0196: * }
0197: * </pre>
0198: */
0199: public void testBasic() {
0200: {
0201: Label L0 = new Label();
0202: Label L1 = new Label();
0203: Label L2 = new Label();
0204: Label L3 = new Label();
0205: Label L4 = new Label();
0206:
0207: setCurrent(jsr);
0208: ICONST_0();
0209: ISTORE(1);
0210:
0211: /* L0: body of try block */
0212: LABEL(L0);
0213: IINC(1, 1);
0214: GOTO(L1);
0215:
0216: /* L2: exception handler */
0217: LABEL(L2);
0218: ASTORE(3);
0219: JSR(L3);
0220: ALOAD(3);
0221: ATHROW();
0222:
0223: /* L3: subroutine */
0224: LABEL(L3);
0225: ASTORE(2);
0226: IINC(1, -1);
0227: RET(2);
0228:
0229: /* L1: non-exceptional exit from try block */
0230: LABEL(L1);
0231: JSR(L3);
0232: LABEL(L4); // L4
0233: RETURN();
0234:
0235: TRYCATCH(L0, L2, L2);
0236: TRYCATCH(L1, L4, L2);
0237:
0238: END(1, 4);
0239: }
0240:
0241: {
0242: Label L0 = new Label();
0243: Label L1 = new Label();
0244: Label L2 = new Label();
0245: Label L3_1a = new Label();
0246: Label L3_1b = new Label();
0247: Label L3_2a = new Label();
0248: Label L3_2b = new Label();
0249: Label L4 = new Label();
0250:
0251: setCurrent(exp);
0252: ICONST_0();
0253: ISTORE(1);
0254: // L0: try/catch block
0255: LABEL(L0);
0256: IINC(1, 1);
0257: GOTO(L1);
0258:
0259: // L2: Exception handler:
0260: LABEL(L2);
0261: ASTORE(3);
0262: ACONST_NULL();
0263: GOTO(L3_1a);
0264: LABEL(L3_1b); // L3_1b;
0265: ALOAD(3);
0266: ATHROW();
0267:
0268: // L1: On non-exceptional exit, try block leads here:
0269: LABEL(L1);
0270: ACONST_NULL();
0271: GOTO(L3_2a);
0272: LABEL(L3_2b); // L3_2b
0273: LABEL(L4); // L4
0274: RETURN();
0275:
0276: // L3_1a: First instantiation of subroutine:
0277: LABEL(L3_1a);
0278: ASTORE(2);
0279: IINC(1, -1);
0280: GOTO(L3_1b);
0281: LABEL(new Label()); // extra label emitted due to impl quirks
0282:
0283: // L3_2a: Second instantiation of subroutine:
0284: LABEL(L3_2a);
0285: ASTORE(2);
0286: IINC(1, -1);
0287: GOTO(L3_2b);
0288: LABEL(new Label()); // extra label emitted due to impl quirks
0289:
0290: TRYCATCH(L0, L2, L2);
0291: TRYCATCH(L1, L4, L2);
0292:
0293: END(1, 4);
0294: }
0295:
0296: assertEquals(exp, jsr);
0297: }
0298:
0299: /**
0300: * Tests a method which has an if/else-if w/in the finally clause:
0301: *
0302: * <pre>
0303: * public void a() {
0304: * int a = 0;
0305: * try {
0306: * a++;
0307: * } finally {
0308: * if (a == 0)
0309: * a+=2;
0310: * else
0311: * a+=3;
0312: * }
0313: * }
0314: * </pre>
0315: */
0316: public void testIfElseInFinally() {
0317: {
0318: Label L0 = new Label();
0319: Label L1 = new Label();
0320: Label L2 = new Label();
0321: Label L3 = new Label();
0322: Label L4 = new Label();
0323: Label L5 = new Label();
0324: Label L6 = new Label();
0325:
0326: setCurrent(jsr);
0327: ICONST_0();
0328: ISTORE(1);
0329:
0330: /* L0: body of try block */
0331: LABEL(L0);
0332: IINC(1, 1);
0333: GOTO(L1);
0334:
0335: /* L2: exception handler */
0336: LABEL(L2);
0337: ASTORE(3);
0338: JSR(L3);
0339: ALOAD(3);
0340: ATHROW();
0341:
0342: /* L3: subroutine */
0343: LABEL(L3);
0344: ASTORE(2);
0345: ILOAD(1);
0346: IFNE(L4);
0347: IINC(1, 2);
0348: GOTO(L5);
0349: LABEL(L4); // L4: a != 0
0350: IINC(1, 3);
0351: LABEL(L5); // L5: common exit
0352: RET(2);
0353:
0354: /* L1: non-exceptional exit from try block */
0355: LABEL(L1);
0356: JSR(L3);
0357: LABEL(L6); // L6 is used in the TRYCATCH below
0358: RETURN();
0359:
0360: TRYCATCH(L0, L2, L2);
0361: TRYCATCH(L1, L6, L2);
0362:
0363: END(1, 4);
0364: }
0365:
0366: {
0367: Label L0 = new Label();
0368: Label L1 = new Label();
0369: Label L2 = new Label();
0370: Label L3_1a = new Label();
0371: Label L3_1b = new Label();
0372: Label L3_2a = new Label();
0373: Label L3_2b = new Label();
0374: Label L4_1 = new Label();
0375: Label L4_2 = new Label();
0376: Label L5_1 = new Label();
0377: Label L5_2 = new Label();
0378: Label L6 = new Label();
0379:
0380: setCurrent(exp);
0381: ICONST_0();
0382: ISTORE(1);
0383: // L0: try/catch block
0384: LABEL(L0);
0385: IINC(1, 1);
0386: GOTO(L1);
0387:
0388: // L2: Exception handler:
0389: LABEL(L2);
0390: ASTORE(3);
0391: ACONST_NULL();
0392: GOTO(L3_1a);
0393: LABEL(L3_1b); // L3_1b;
0394: ALOAD(3);
0395: ATHROW();
0396:
0397: // L1: On non-exceptional exit, try block leads here:
0398: LABEL(L1);
0399: ACONST_NULL();
0400: GOTO(L3_2a);
0401: LABEL(L3_2b); // L3_2b
0402: LABEL(L6); // L6
0403: RETURN();
0404:
0405: // L3_1a: First instantiation of subroutine:
0406: LABEL(L3_1a);
0407: ASTORE(2);
0408: ILOAD(1);
0409: IFNE(L4_1);
0410: IINC(1, 2);
0411: GOTO(L5_1);
0412: LABEL(L4_1); // L4_1: a != 0
0413: IINC(1, 3);
0414: LABEL(L5_1); // L5_1: common exit
0415: GOTO(L3_1b);
0416: LABEL(new Label()); // extra label emitted due to impl quirks
0417:
0418: // L3_2a: First instantiation of subroutine:
0419: LABEL(L3_2a);
0420: ASTORE(2);
0421: ILOAD(1);
0422: IFNE(L4_2);
0423: IINC(1, 2);
0424: GOTO(L5_2);
0425: LABEL(L4_2); // L4_2: a != 0
0426: IINC(1, 3);
0427: LABEL(L5_2); // L5_2: common exit
0428: GOTO(L3_2b);
0429: LABEL(new Label()); // extra label emitted due to impl quirks
0430:
0431: TRYCATCH(L0, L2, L2);
0432: TRYCATCH(L1, L6, L2);
0433:
0434: END(1, 4);
0435: }
0436:
0437: assertEquals(exp, jsr);
0438: }
0439:
0440: /**
0441: * Tests a simple nested finally:
0442: *
0443: * <pre>
0444: * public void a1() {
0445: * int a = 0;
0446: * try {
0447: * a += 1;
0448: * } finally {
0449: * try {
0450: * a += 2;
0451: * } finally {
0452: * a += 3;
0453: * }
0454: * }
0455: * }
0456: * </pre>
0457: */
0458: public void testSimpleNestedFinally() {
0459: {
0460: Label L0 = new Label();
0461: Label L1 = new Label();
0462: Label L2 = new Label();
0463: Label L3 = new Label();
0464: Label L4 = new Label();
0465: Label L5 = new Label();
0466:
0467: setCurrent(jsr);
0468:
0469: ICONST_0();
0470: ISTORE(1);
0471:
0472: // L0: Body of try block:
0473: LABEL(L0);
0474: IINC(1, 1);
0475: JSR(L3);
0476: GOTO(L1);
0477:
0478: // L2: First exception handler:
0479: LABEL(L2);
0480: JSR(L3);
0481: ATHROW();
0482:
0483: // L3: First subroutine:
0484: LABEL(L3);
0485: ASTORE(2);
0486: IINC(1, 2);
0487: JSR(L4);
0488: RET(2);
0489:
0490: // L5: Second exception handler:
0491: LABEL(L5);
0492: JSR(L4);
0493: ATHROW();
0494:
0495: // L4: Second subroutine:
0496: LABEL(L4);
0497: ASTORE(3);
0498: IINC(1, 3);
0499: RET(3);
0500:
0501: // L1: On normal exit, try block jumps here:
0502: LABEL(L1);
0503: RETURN();
0504:
0505: TRYCATCH(L0, L2, L2);
0506: TRYCATCH(L3, L5, L5);
0507:
0508: END(2, 6);
0509: }
0510:
0511: {
0512: Label L0 = new Label();
0513: Label L1 = new Label();
0514: Label L2 = new Label();
0515: Label L3_1a = new Label();
0516: Label L3_1b = new Label();
0517: Label L3_2a = new Label();
0518: Label L3_2b = new Label();
0519: Label L4_1a = new Label();
0520: Label L4_1b = new Label();
0521: Label L4_2a = new Label();
0522: Label L4_2b = new Label();
0523: Label L4_3a = new Label();
0524: Label L4_3b = new Label();
0525: Label L4_4a = new Label();
0526: Label L4_4b = new Label();
0527: Label L5_1 = new Label();
0528: Label L5_2 = new Label();
0529:
0530: setCurrent(exp);
0531:
0532: ICONST_0();
0533: ISTORE(1);
0534:
0535: // L0: Body of try block:
0536: LABEL(L0);
0537: IINC(1, 1);
0538: ACONST_NULL();
0539: GOTO(L3_1a);
0540: LABEL(L3_1b); // L3_1b
0541: GOTO(L1);
0542:
0543: // L2: First exception handler:
0544: LABEL(L2);
0545: ACONST_NULL();
0546: GOTO(L3_2a);
0547: LABEL(L3_2b); // L3_2b
0548: ATHROW();
0549:
0550: // L1: On normal exit, try block jumps here:
0551: LABEL(L1);
0552: RETURN();
0553:
0554: // L3_1a: First instantiation of first subroutine:
0555: LABEL(L3_1a);
0556: ASTORE(2);
0557: IINC(1, 2);
0558: ACONST_NULL();
0559: GOTO(L4_1a);
0560: LABEL(L4_1b); // L4_1b
0561: GOTO(L3_1b);
0562: LABEL(L5_1); // L5_1
0563: ACONST_NULL();
0564: GOTO(L4_2a);
0565: LABEL(L4_2b); // L4_2b
0566: ATHROW();
0567: LABEL(new Label()); // extra label emitted due to impl quirks
0568:
0569: // L3_2a: Second instantiation of first subroutine:
0570: LABEL(L3_2a);
0571: ASTORE(2);
0572: IINC(1, 2);
0573: ACONST_NULL();
0574: GOTO(L4_3a);
0575: LABEL(L4_3b); // L4_3b
0576: GOTO(L3_2b);
0577: LABEL(L5_2); // L5_2
0578: ACONST_NULL();
0579: GOTO(L4_4a);
0580: LABEL(L4_4b); // L4_4b
0581: ATHROW();
0582: LABEL(new Label()); // extra label emitted due to impl quirks
0583:
0584: // L4_1a: First instantiation of second subroutine:
0585: LABEL(L4_1a);
0586: ASTORE(3);
0587: IINC(1, 3);
0588: GOTO(L4_1b);
0589: LABEL(new Label()); // extra label emitted due to impl quirks
0590:
0591: // L4_2a: Second instantiation of second subroutine:
0592: LABEL(L4_2a);
0593: ASTORE(3);
0594: IINC(1, 3);
0595: GOTO(L4_2b);
0596: LABEL(new Label()); // extra label emitted due to impl quirks
0597:
0598: // L4_3a: Third instantiation of second subroutine:
0599: LABEL(L4_3a);
0600: ASTORE(3);
0601: IINC(1, 3);
0602: GOTO(L4_3b);
0603: LABEL(new Label()); // extra label emitted due to impl quirks
0604:
0605: // L4_4a: Fourth instantiation of second subroutine:
0606: LABEL(L4_4a);
0607: ASTORE(3);
0608: IINC(1, 3);
0609: GOTO(L4_4b);
0610: LABEL(new Label()); // extra label emitted due to impl quirks
0611:
0612: TRYCATCH(L0, L2, L2);
0613: TRYCATCH(L3_1a, L5_1, L5_1);
0614: TRYCATCH(L3_2a, L5_2, L5_2);
0615:
0616: END(2, 6);
0617: }
0618:
0619: assertEquals(exp, jsr);
0620: }
0621:
0622: /**
0623: * This tests a subroutine which has no ret statement, but ends in a
0624: * "return" instead.
0625: *
0626: * We structure this as a try/finally with a break in the finally. Because
0627: * the while loop is infinite, it's clear from the byte code that the only
0628: * path which reaches the RETURN instruction is through the subroutine.
0629: *
0630: * <pre>
0631: * public void a1() {
0632: * int a = 0;
0633: * while (true) {
0634: * try {
0635: * a += 1;
0636: * } finally {
0637: * a += 2;
0638: * break;
0639: * }
0640: * }
0641: * }
0642: * </pre>
0643: */
0644: public void testSubroutineWithNoRet() {
0645: {
0646: Label L0 = new Label();
0647: Label L1 = new Label();
0648: Label L2 = new Label();
0649: Label L3 = new Label();
0650: Label L4 = new Label();
0651:
0652: setCurrent(jsr);
0653: ICONST_0();
0654: ISTORE(1);
0655:
0656: // L0: while loop header/try block
0657: LABEL(L0);
0658: IINC(1, 1);
0659: JSR(L1);
0660: GOTO(L2);
0661:
0662: // L3: implicit catch block
0663: LABEL(L3);
0664: ASTORE(2);
0665: JSR(L1);
0666: ALOAD(2);
0667: ATHROW();
0668:
0669: // L1: subroutine ...
0670: LABEL(L1);
0671: ASTORE(3);
0672: IINC(1, 2);
0673: GOTO(L4); // ...not that it does not return!
0674:
0675: // L2: end of the loop... goes back to the top!
0676: LABEL(L2);
0677: GOTO(L0);
0678:
0679: // L4:
0680: LABEL(L4);
0681: RETURN();
0682:
0683: TRYCATCH(L0, L3, L3);
0684:
0685: END(1, 4);
0686: }
0687:
0688: {
0689: Label L0 = new Label();
0690: Label L1_1a = new Label();
0691: Label L1_1b = new Label();
0692: Label L1_2a = new Label();
0693: Label L1_2b = new Label();
0694: Label L2 = new Label();
0695: Label L3 = new Label();
0696: Label L4_1 = new Label();
0697: Label L4_2 = new Label();
0698:
0699: setCurrent(exp);
0700: ICONST_0();
0701: ISTORE(1);
0702:
0703: // L0: while loop header/try block
0704: LABEL(L0);
0705: IINC(1, 1);
0706: ACONST_NULL();
0707: GOTO(L1_1a);
0708: LABEL(L1_1b); // L1_1b
0709: GOTO(L2);
0710:
0711: // L3: implicit catch block
0712: LABEL(L3);
0713: ASTORE(2);
0714: ACONST_NULL();
0715: GOTO(L1_2a);
0716: LABEL(L1_2b); // L1_2b
0717: ALOAD(2);
0718: ATHROW();
0719:
0720: // L2: end of the loop... goes back to the top!
0721: LABEL(L2);
0722: GOTO(L0);
0723: LABEL(new Label()); // extra label emitted due to impl quirks
0724:
0725: // L1_1a: first instantiation of subroutine ...
0726: LABEL(L1_1a);
0727: ASTORE(3);
0728: IINC(1, 2);
0729: GOTO(L4_1); // ...not that it does not return!
0730: LABEL(L4_1);
0731: RETURN();
0732:
0733: // L1_2a: second instantiation of subroutine ...
0734: LABEL(L1_2a);
0735: ASTORE(3);
0736: IINC(1, 2);
0737: GOTO(L4_2); // ...not that it does not return!
0738: LABEL(L4_2);
0739: RETURN();
0740:
0741: TRYCATCH(L0, L3, L3);
0742:
0743: END(1, 4);
0744: }
0745:
0746: assertEquals(exp, jsr);
0747: }
0748:
0749: /**
0750: * This tests a subroutine which has no ret statement, but ends in a
0751: * "return" instead.
0752: *
0753: * <pre>
0754: * JSR L0
0755: * L0:
0756: * ASTORE 0
0757: * RETURN
0758: * </pre>
0759: */
0760: public void testSubroutineWithNoRet2() {
0761: {
0762: Label L0 = new Label();
0763:
0764: setCurrent(jsr);
0765: JSR(L0);
0766: LABEL(L0);
0767: ASTORE(0);
0768: RETURN();
0769: END(1, 1);
0770: }
0771:
0772: {
0773: Label L0_1a = new Label();
0774: Label L0_1b = new Label();
0775:
0776: setCurrent(exp);
0777:
0778: ACONST_NULL();
0779: GOTO(L0_1a);
0780: LABEL(L0_1b);
0781:
0782: // L0_1a: First instantiation of subroutine:
0783: LABEL(L0_1a);
0784: ASTORE(0);
0785: RETURN();
0786: LABEL(new Label()); // extra label emitted due to impl quirks
0787:
0788: END(1, 1);
0789: }
0790:
0791: assertEquals(exp, jsr);
0792: }
0793:
0794: /**
0795: * This tests a subroutine which has no ret statement, but instead exits
0796: * implicitely by branching to code which is not part of the subroutine.
0797: * (Sadly, this is legal)
0798: *
0799: * We structure this as a try/finally in a loop with a break in the finally.
0800: * The loop is not trivially infinite, so the RETURN statement is reachable
0801: * both from the JSR subroutine and from the main entry point.
0802: *
0803: * <pre>
0804: * public void a1() {
0805: * int a = 0;
0806: * while (null == null) {
0807: * try {
0808: * a += 1;
0809: * } finally {
0810: * a += 2;
0811: * break;
0812: * }
0813: * }
0814: * }
0815: * </pre>
0816: */
0817: public void testImplicitExit() {
0818: {
0819: Label L0 = new Label();
0820: Label L1 = new Label();
0821: Label L2 = new Label();
0822: Label L3 = new Label();
0823: Label L4 = new Label();
0824: Label L5 = new Label();
0825:
0826: setCurrent(jsr);
0827: ICONST_0();
0828: ISTORE(1);
0829:
0830: // L5: while loop header
0831: LABEL(L5);
0832: ACONST_NULL();
0833: IFNONNULL(L4);
0834:
0835: // L0: try block
0836: LABEL(L0);
0837: IINC(1, 1);
0838: JSR(L1);
0839: GOTO(L2);
0840:
0841: // L3: implicit catch block
0842: LABEL(L3);
0843: ASTORE(2);
0844: JSR(L1);
0845: ALOAD(2);
0846: ATHROW();
0847:
0848: // L1: subroutine ...
0849: LABEL(L1);
0850: ASTORE(3);
0851: IINC(1, 2);
0852: GOTO(L4); // ...not that it does not return!
0853:
0854: // L2: end of the loop... goes back to the top!
0855: LABEL(L2);
0856: GOTO(L0);
0857:
0858: // L4:
0859: LABEL(L4);
0860: RETURN();
0861:
0862: TRYCATCH(L0, L3, L3);
0863:
0864: END(1, 4);
0865: }
0866:
0867: {
0868: Label L0 = new Label();
0869: Label L1_1a = new Label();
0870: Label L1_1b = new Label();
0871: Label L1_2a = new Label();
0872: Label L1_2b = new Label();
0873: Label L2 = new Label();
0874: Label L3 = new Label();
0875: Label L4 = new Label();
0876: Label L5 = new Label();
0877:
0878: setCurrent(exp);
0879: ICONST_0();
0880: ISTORE(1);
0881:
0882: // L5: while loop header
0883: LABEL(L5);
0884: ACONST_NULL();
0885: IFNONNULL(L4);
0886:
0887: // L0: while loop header/try block
0888: LABEL(L0);
0889: IINC(1, 1);
0890: ACONST_NULL();
0891: GOTO(L1_1a);
0892: LABEL(L1_1b); // L1_1b
0893: GOTO(L2);
0894:
0895: // L3: implicit catch block
0896: LABEL(L3);
0897: ASTORE(2);
0898: ACONST_NULL();
0899: GOTO(L1_2a);
0900: LABEL(L1_2b); // L1_2b
0901: ALOAD(2);
0902: ATHROW();
0903:
0904: // L2: end of the loop... goes back to the top!
0905: LABEL(L2);
0906: GOTO(L0);
0907:
0908: // L4: exit, not part of subroutine
0909: // Note that the two subroutine instantiations branch here
0910: LABEL(L4);
0911: RETURN();
0912:
0913: // L1_1a: first instantiation of subroutine ...
0914: LABEL(L1_1a);
0915: ASTORE(3);
0916: IINC(1, 2);
0917: GOTO(L4); // ...note that it does not return!
0918: LABEL(new Label()); // extra label emitted due to impl quirks
0919:
0920: // L1_2a: second instantiation of subroutine ...
0921: LABEL(L1_2a);
0922: ASTORE(3);
0923: IINC(1, 2);
0924: GOTO(L4); // ...note that it does not return!
0925: LABEL(new Label()); // extra label emitted due to impl quirks
0926:
0927: TRYCATCH(L0, L3, L3);
0928:
0929: END(1, 4);
0930: }
0931:
0932: assertEquals(exp, jsr);
0933: }
0934:
0935: /**
0936: * Tests a nested try/finally with implicit exit from one subroutine to the
0937: * other subroutine. Equivalent to the following java code:
0938: *
0939: * <pre>
0940: * void m(boolean b) {
0941: * try {
0942: * return;
0943: * } finally {
0944: * while (b) {
0945: * try {
0946: * return;
0947: * } finally {
0948: * // NOTE --- this break avoids the second return above (weird)
0949: * if (b) break;
0950: * }
0951: * }
0952: * }
0953: * }
0954: * </pre>
0955: *
0956: * This example is from the paper, "Subroutine Inlining and Bytecode
0957: * Abstraction to Simplify Static and Dynamic Analysis" by Cyrille Artho and
0958: * Armin Biere.
0959: */
0960: public void testImplicitExitToAnotherSubroutine() {
0961: {
0962: Label T1 = new Label();
0963: Label C1 = new Label();
0964: Label S1 = new Label();
0965: Label L = new Label();
0966: Label C2 = new Label();
0967: Label S2 = new Label();
0968: Label W = new Label();
0969: Label X = new Label();
0970:
0971: // variable numbers:
0972: int b = 1;
0973: int e1 = 2;
0974: int e2 = 3;
0975: int r1 = 4;
0976: int r2 = 5;
0977:
0978: setCurrent(jsr);
0979:
0980: ICONST_0();
0981: ISTORE(1);
0982:
0983: // T1: first try:
0984: LABEL(T1);
0985: JSR(S1);
0986: RETURN();
0987:
0988: // C1: exception handler for first try
0989: LABEL(C1);
0990: ASTORE(e1);
0991: JSR(S1);
0992: ALOAD(e1);
0993: ATHROW();
0994:
0995: // S1: first finally handler
0996: LABEL(S1);
0997: ASTORE(r1);
0998: GOTO(W);
0999:
1000: // L: body of while loop, also second try
1001: LABEL(L);
1002: JSR(S2);
1003: RETURN();
1004:
1005: // C2: exception handler for second try
1006: LABEL(C2);
1007: ASTORE(e2);
1008: JSR(S2);
1009: ALOAD(e2);
1010: ATHROW();
1011:
1012: // S2: second finally handler
1013: LABEL(S2);
1014: ASTORE(r2);
1015: ILOAD(b);
1016: IFNE(X);
1017: RET(r2);
1018:
1019: // W: test for the while loop
1020: LABEL(W);
1021: ILOAD(b);
1022: IFNE(L); // falls through to X
1023:
1024: // X: exit from finally{} block
1025: LABEL(X);
1026: RET(r1);
1027:
1028: TRYCATCH(T1, C1, C1);
1029: TRYCATCH(L, C2, C2);
1030:
1031: END(1, 6);
1032: }
1033:
1034: {
1035: Label T1 = new Label();
1036: Label C1 = new Label();
1037: Label S1_1a = new Label();
1038: Label S1_1b = new Label();
1039: Label S1_2a = new Label();
1040: Label S1_2b = new Label();
1041: Label L_1 = new Label();
1042: Label L_2 = new Label();
1043: Label C2_1 = new Label();
1044: Label C2_2 = new Label();
1045: Label S2_1_1a = new Label();
1046: Label S2_1_1b = new Label();
1047: Label S2_1_2a = new Label();
1048: Label S2_1_2b = new Label();
1049: Label S2_2_1a = new Label();
1050: Label S2_2_1b = new Label();
1051: Label S2_2_2a = new Label();
1052: Label S2_2_2b = new Label();
1053: Label W_1 = new Label();
1054: Label W_2 = new Label();
1055: Label X_1 = new Label();
1056: Label X_2 = new Label();
1057:
1058: // variable numbers:
1059: int b = 1;
1060: int e1 = 2;
1061: int e2 = 3;
1062: int r1 = 4;
1063: int r2 = 5;
1064:
1065: setCurrent(exp);
1066:
1067: // --- Main Subroutine ---
1068:
1069: ICONST_0();
1070: ISTORE(1);
1071:
1072: // T1: first try:
1073: LABEL(T1);
1074: ACONST_NULL();
1075: GOTO(S1_1a);
1076: LABEL(S1_1b);
1077: RETURN();
1078:
1079: // C1: exception handler for first try
1080: LABEL(C1);
1081: ASTORE(e1);
1082: ACONST_NULL();
1083: GOTO(S1_2a);
1084: LABEL(S1_2b);
1085: ALOAD(e1);
1086: ATHROW();
1087: LABEL(new Label()); // extra label emitted due to impl quirks
1088:
1089: // --- First instantiation of first subroutine ---
1090:
1091: // S1: first finally handler
1092: LABEL(S1_1a);
1093: ASTORE(r1);
1094: GOTO(W_1);
1095:
1096: // L_1: body of while loop, also second try
1097: LABEL(L_1);
1098: ACONST_NULL();
1099: GOTO(S2_1_1a);
1100: LABEL(S2_1_1b);
1101: RETURN();
1102:
1103: // C2_1: exception handler for second try
1104: LABEL(C2_1);
1105: ASTORE(e2);
1106: ACONST_NULL();
1107: GOTO(S2_1_2a);
1108: LABEL(S2_1_2b);
1109: ALOAD(e2);
1110: ATHROW();
1111:
1112: // W_1: test for the while loop
1113: LABEL(W_1);
1114: ILOAD(b);
1115: IFNE(L_1); // falls through to X_1
1116:
1117: // X_1: exit from finally{} block
1118: LABEL(X_1);
1119: GOTO(S1_1b);
1120:
1121: // --- Second instantiation of first subroutine ---
1122:
1123: // S1: first finally handler
1124: LABEL(S1_2a);
1125: ASTORE(r1);
1126: GOTO(W_2);
1127:
1128: // L_2: body of while loop, also second try
1129: LABEL(L_2);
1130: ACONST_NULL();
1131: GOTO(S2_2_1a);
1132: LABEL(S2_2_1b);
1133: RETURN();
1134:
1135: // C2_2: exception handler for second try
1136: LABEL(C2_2);
1137: ASTORE(e2);
1138: ACONST_NULL();
1139: GOTO(S2_2_2a);
1140: LABEL(S2_2_2b);
1141: ALOAD(e2);
1142: ATHROW();
1143:
1144: // W_2: test for the while loop
1145: LABEL(W_2);
1146: ILOAD(b);
1147: IFNE(L_2); // falls through to X_2
1148:
1149: // X_2: exit from finally{} block
1150: LABEL(X_2);
1151: GOTO(S1_2b);
1152:
1153: // --- Second subroutine's 4 instantiations ---
1154:
1155: // S2_1_1a:
1156: LABEL(S2_1_1a);
1157: ASTORE(r2);
1158: ILOAD(b);
1159: IFNE(X_1);
1160: GOTO(S2_1_1b);
1161: LABEL(new Label()); // extra label emitted due to impl quirks
1162:
1163: // S2_1_2a:
1164: LABEL(S2_1_2a);
1165: ASTORE(r2);
1166: ILOAD(b);
1167: IFNE(X_1);
1168: GOTO(S2_1_2b);
1169: LABEL(new Label()); // extra label emitted due to impl quirks
1170:
1171: // S2_2_1a:
1172: LABEL(S2_2_1a);
1173: ASTORE(r2);
1174: ILOAD(b);
1175: IFNE(X_2);
1176: GOTO(S2_2_1b);
1177: LABEL(new Label()); // extra label emitted due to impl quirks
1178:
1179: // S2_2_2a:
1180: LABEL(S2_2_2a);
1181: ASTORE(r2);
1182: ILOAD(b);
1183: IFNE(X_2);
1184: GOTO(S2_2_2b);
1185: LABEL(new Label()); // extra label emitted due to impl quirks
1186:
1187: TRYCATCH(T1, C1, C1);
1188: TRYCATCH(L_1, C2_1, C2_1); // duplicated try/finally for each...
1189: TRYCATCH(L_2, C2_2, C2_2); // ...instantiation of first sub
1190:
1191: END(1, 6);
1192: }
1193:
1194: assertEquals(exp, jsr);
1195: }
1196:
1197: /**
1198: * This tests two subroutines, neither of which exit. Instead, they both
1199: * branch to a common set of code which returns from the method. This code
1200: * is not reachable except through these subroutines, and since they do not
1201: * invoke each other, it must be copied into both of them.
1202: *
1203: * I don't believe this can be represented in Java.
1204: */
1205: public void testCommonCodeWhichMustBeDuplicated() {
1206: {
1207: Label L1 = new Label();
1208: Label L2 = new Label();
1209: Label L3 = new Label();
1210:
1211: setCurrent(jsr);
1212: ICONST_0();
1213: ISTORE(1);
1214:
1215: // Invoke the two subroutines, each twice:
1216: JSR(L1);
1217: JSR(L1);
1218: JSR(L2);
1219: JSR(L2);
1220: RETURN();
1221:
1222: // L1: subroutine 1
1223: LABEL(L1);
1224: IINC(1, 1);
1225: GOTO(L3); // ...note that it does not return!
1226:
1227: // L2: subroutine 2
1228: LABEL(L2);
1229: IINC(1, 2);
1230: GOTO(L3); // ...note that it does not return!
1231:
1232: // L3: common code to both subroutines: exit method
1233: LABEL(L3);
1234: RETURN();
1235:
1236: END(1, 2);
1237: }
1238:
1239: {
1240: Label L1_1a = new Label();
1241: Label L1_1b = new Label();
1242: Label L1_2a = new Label();
1243: Label L1_2b = new Label();
1244: Label L2_1a = new Label();
1245: Label L2_1b = new Label();
1246: Label L2_2a = new Label();
1247: Label L2_2b = new Label();
1248: Label L3_1 = new Label();
1249: Label L3_2 = new Label();
1250: Label L3_3 = new Label();
1251: Label L3_4 = new Label();
1252:
1253: setCurrent(exp);
1254: ICONST_0();
1255: ISTORE(1);
1256:
1257: // Invoke the two subroutines, each twice:
1258: ACONST_NULL();
1259: GOTO(L1_1a);
1260: LABEL(L1_1b);
1261: ACONST_NULL();
1262: GOTO(L1_2a);
1263: LABEL(L1_2b);
1264: ACONST_NULL();
1265: GOTO(L2_1a);
1266: LABEL(L2_1b);
1267: ACONST_NULL();
1268: GOTO(L2_2a);
1269: LABEL(L2_2b);
1270: RETURN();
1271: LABEL(new Label()); // extra label emitted due to impl quirks
1272:
1273: // L1_1a: instantiation 1 of subroutine 1
1274: LABEL(L1_1a);
1275: IINC(1, 1);
1276: GOTO(L3_1); // ...note that it does not return!
1277: LABEL(L3_1);
1278: RETURN();
1279:
1280: // L1_2a: instantiation 2 of subroutine 1
1281: LABEL(L1_2a);
1282: IINC(1, 1);
1283: GOTO(L3_2); // ...note that it does not return!
1284: LABEL(L3_2);
1285: RETURN();
1286:
1287: // L2_1a: instantiation 1 of subroutine 2
1288: LABEL(L2_1a);
1289: IINC(1, 2);
1290: GOTO(L3_3); // ...note that it does not return!
1291: LABEL(L3_3);
1292: RETURN();
1293:
1294: // L2_2a: instantiation 2 of subroutine 2
1295: LABEL(L2_2a);
1296: IINC(1, 2);
1297: GOTO(L3_4); // ...note that it does not return!
1298: LABEL(L3_4);
1299: RETURN();
1300:
1301: END(1, 2);
1302: }
1303:
1304: assertEquals(exp, jsr);
1305: }
1306:
1307: /**
1308: * This tests a simple subroutine where the control flow jumps back and
1309: * forth between the subroutine and the caller.
1310: *
1311: * This would not normally be produced by a java compiler.
1312: */
1313: public void testInterleavedCode() {
1314: {
1315: Label L1 = new Label();
1316: Label L2 = new Label();
1317: Label L3 = new Label();
1318: Label L4 = new Label();
1319:
1320: setCurrent(jsr);
1321: ICONST_0();
1322: ISTORE(1);
1323:
1324: // Invoke the subroutine, each twice:
1325: JSR(L1);
1326: GOTO(L2);
1327:
1328: // L1: subroutine 1
1329: LABEL(L1);
1330: ASTORE(2);
1331: IINC(1, 1);
1332: GOTO(L3);
1333:
1334: // L2: second part of main subroutine
1335: LABEL(L2);
1336: IINC(1, 2);
1337: GOTO(L4);
1338:
1339: // L3: second part of subroutine 1
1340: LABEL(L3);
1341: IINC(1, 4);
1342: RET(2);
1343:
1344: // L4: third part of main subroutine
1345: LABEL(L4);
1346: JSR(L1);
1347: RETURN();
1348:
1349: END(1, 3);
1350: }
1351:
1352: {
1353: Label L1_1a = new Label();
1354: Label L1_1b = new Label();
1355: Label L1_2a = new Label();
1356: Label L1_2b = new Label();
1357: Label L2 = new Label();
1358: Label L3_1 = new Label();
1359: Label L3_2 = new Label();
1360: Label L4 = new Label();
1361:
1362: setCurrent(exp);
1363:
1364: // Main routine:
1365: ICONST_0();
1366: ISTORE(1);
1367: ACONST_NULL();
1368: GOTO(L1_1a);
1369: LABEL(L1_1b);
1370: GOTO(L2);
1371: LABEL(L2);
1372: IINC(1, 2);
1373: GOTO(L4);
1374: LABEL(L4);
1375: ACONST_NULL();
1376: GOTO(L1_2a);
1377: LABEL(L1_2b);
1378: RETURN();
1379:
1380: // L1_1: instantiation #1
1381: LABEL(L1_1a);
1382: ASTORE(2);
1383: IINC(1, 1);
1384: GOTO(L3_1);
1385: LABEL(L3_1);
1386: IINC(1, 4);
1387: GOTO(L1_1b);
1388: LABEL(new Label()); // extra label emitted due to impl quirks
1389:
1390: // L1_2: instantiation #2
1391: LABEL(L1_2a);
1392: ASTORE(2);
1393: IINC(1, 1);
1394: GOTO(L3_2);
1395: LABEL(L3_2);
1396: IINC(1, 4);
1397: GOTO(L1_2b);
1398: LABEL(new Label()); // extra label emitted due to impl quirks
1399:
1400: END(1, 3);
1401: }
1402:
1403: assertEquals(exp, jsr);
1404: }
1405:
1406: /**
1407: * Tests a nested try/finally with implicit exit from one subroutine to the
1408: * other subroutine, and with a surrounding try/catch thrown in the mix.
1409: * Equivalent to the following java code:
1410: *
1411: * <pre>
1412: * void m(int b) {
1413: * try {
1414: * try {
1415: * return;
1416: * } finally {
1417: * while (b) {
1418: * try {
1419: * return;
1420: * } finally {
1421: * // NOTE --- this break avoids the second return above (weird)
1422: * if (b) break;
1423: * }
1424: * }
1425: * }
1426: * } catch (Exception e) {
1427: * b += 3;
1428: * return;
1429: * }
1430: * }
1431: * </pre>
1432: */
1433: public void testImplicitExitInTryCatch() {
1434: {
1435: Label T1 = new Label();
1436: Label C1 = new Label();
1437: Label S1 = new Label();
1438: Label L = new Label();
1439: Label C2 = new Label();
1440: Label S2 = new Label();
1441: Label W = new Label();
1442: Label X = new Label();
1443: Label OT = new Label();
1444: Label OC = new Label();
1445:
1446: // variable numbers:
1447: int b = 1;
1448: int e1 = 2;
1449: int e2 = 3;
1450: int r1 = 4;
1451: int r2 = 5;
1452:
1453: setCurrent(jsr);
1454:
1455: ICONST_0();
1456: ISTORE(1);
1457:
1458: // OT: outermost try
1459: LABEL(OT);
1460:
1461: // T1: first try:
1462: LABEL(T1);
1463: JSR(S1);
1464: RETURN();
1465:
1466: // C1: exception handler for first try
1467: LABEL(C1);
1468: ASTORE(e1);
1469: JSR(S1);
1470: ALOAD(e1);
1471: ATHROW();
1472:
1473: // S1: first finally handler
1474: LABEL(S1);
1475: ASTORE(r1);
1476: GOTO(W);
1477:
1478: // L: body of while loop, also second try
1479: LABEL(L);
1480: JSR(S2);
1481: RETURN();
1482:
1483: // C2: exception handler for second try
1484: LABEL(C2);
1485: ASTORE(e2);
1486: JSR(S2);
1487: ALOAD(e2);
1488: ATHROW();
1489:
1490: // S2: second finally handler
1491: LABEL(S2);
1492: ASTORE(r2);
1493: ILOAD(b);
1494: IFNE(X);
1495: RET(r2);
1496:
1497: // W: test for the while loop
1498: LABEL(W);
1499: ILOAD(b);
1500: IFNE(L); // falls through to X
1501:
1502: // X: exit from finally{} block
1503: LABEL(X);
1504: RET(r1);
1505:
1506: // OC: outermost catch
1507: LABEL(OC);
1508: IINC(b, 3);
1509: RETURN();
1510:
1511: TRYCATCH(T1, C1, C1);
1512: TRYCATCH(L, C2, C2);
1513: TRYCATCH(OT, OC, OC);
1514:
1515: END(1, 6);
1516: }
1517:
1518: {
1519: Label T1 = new Label();
1520: Label C1 = new Label();
1521: Label S1_1a = new Label();
1522: Label S1_1b = new Label();
1523: Label S1_2a = new Label();
1524: Label S1_2b = new Label();
1525: Label L_1 = new Label();
1526: Label L_2 = new Label();
1527: Label C2_1 = new Label();
1528: Label C2_2 = new Label();
1529: Label S2_1_1a = new Label();
1530: Label S2_1_1b = new Label();
1531: Label S2_1_2a = new Label();
1532: Label S2_1_2b = new Label();
1533: Label S2_2_1a = new Label();
1534: Label S2_2_1b = new Label();
1535: Label S2_2_2a = new Label();
1536: Label S2_2_2b = new Label();
1537: Label W_1 = new Label();
1538: Label W_2 = new Label();
1539: Label X_1 = new Label();
1540: Label X_2 = new Label();
1541: Label OT_1 = S1_1a;
1542: Label OT_2 = S1_2a;
1543: Label OT_1_1 = S2_1_1a;
1544: Label OT_1_2 = S2_1_2a;
1545: Label OT_2_1 = S2_2_1a;
1546: Label OT_2_2 = S2_2_2a;
1547: Label OC = new Label();
1548: Label OC_1 = new Label();
1549: Label OC_2 = new Label();
1550: Label OC_1_1 = new Label();
1551: Label OC_1_2 = new Label();
1552: Label OC_2_1 = new Label();
1553: Label OC_2_2 = new Label();
1554:
1555: // variable numbers:
1556: int b = 1;
1557: int e1 = 2;
1558: int e2 = 3;
1559: int r1 = 4;
1560: int r2 = 5;
1561:
1562: setCurrent(exp);
1563:
1564: // --- Main Subroutine ---
1565:
1566: ICONST_0();
1567: ISTORE(1);
1568:
1569: // T1: outermost try / first try:
1570: LABEL(T1);
1571: ACONST_NULL();
1572: GOTO(S1_1a);
1573: LABEL(S1_1b);
1574: RETURN();
1575:
1576: // C1: exception handler for first try
1577: LABEL(C1);
1578: ASTORE(e1);
1579: ACONST_NULL();
1580: GOTO(S1_2a);
1581: LABEL(S1_2b);
1582: ALOAD(e1);
1583: ATHROW();
1584:
1585: // OC: Outermost catch
1586: LABEL(OC);
1587: IINC(b, 3);
1588: RETURN();
1589:
1590: // --- First instantiation of first subroutine ---
1591:
1592: // S1: first finally handler
1593: LABEL(S1_1a);
1594: ASTORE(r1);
1595: GOTO(W_1);
1596:
1597: // L_1: body of while loop, also second try
1598: LABEL(L_1);
1599: ACONST_NULL();
1600: GOTO(S2_1_1a);
1601: LABEL(S2_1_1b);
1602: RETURN();
1603:
1604: // C2_1: exception handler for second try
1605: LABEL(C2_1);
1606: ASTORE(e2);
1607: ACONST_NULL();
1608: GOTO(S2_1_2a);
1609: LABEL(S2_1_2b);
1610: ALOAD(e2);
1611: ATHROW();
1612:
1613: // W_1: test for the while loop
1614: LABEL(W_1);
1615: ILOAD(b);
1616: IFNE(L_1); // falls through to X_1
1617:
1618: // X_1: exit from finally{} block
1619: LABEL(X_1);
1620: GOTO(S1_1b);
1621:
1622: LABEL(OC_1);
1623:
1624: // --- Second instantiation of first subroutine ---
1625:
1626: // S1: first finally handler
1627: LABEL(S1_2a);
1628: ASTORE(r1);
1629: GOTO(W_2);
1630:
1631: // L_2: body of while loop, also second try
1632: LABEL(L_2);
1633: ACONST_NULL();
1634: GOTO(S2_2_1a);
1635: LABEL(S2_2_1b);
1636: RETURN();
1637:
1638: // C2_2: exception handler for second try
1639: LABEL(C2_2);
1640: ASTORE(e2);
1641: ACONST_NULL();
1642: GOTO(S2_2_2a);
1643: LABEL(S2_2_2b);
1644: ALOAD(e2);
1645: ATHROW();
1646:
1647: // W_2: test for the while loop
1648: LABEL(W_2);
1649: ILOAD(b);
1650: IFNE(L_2); // falls through to X_2
1651:
1652: // X_2: exit from finally{} block
1653: LABEL(X_2);
1654: GOTO(S1_2b);
1655:
1656: LABEL(OC_2);
1657:
1658: // --- Second subroutine's 4 instantiations ---
1659:
1660: // S2_1_1a:
1661: LABEL(S2_1_1a);
1662: ASTORE(r2);
1663: ILOAD(b);
1664: IFNE(X_1);
1665: GOTO(S2_1_1b);
1666: LABEL(OC_1_1);
1667:
1668: // S2_1_2a:
1669: LABEL(S2_1_2a);
1670: ASTORE(r2);
1671: ILOAD(b);
1672: IFNE(X_1);
1673: GOTO(S2_1_2b);
1674: LABEL(OC_1_2);
1675:
1676: // S2_2_1a:
1677: LABEL(S2_2_1a);
1678: ASTORE(r2);
1679: ILOAD(b);
1680: IFNE(X_2);
1681: GOTO(S2_2_1b);
1682: LABEL(OC_2_1);
1683:
1684: // S2_2_2a:
1685: LABEL(S2_2_2a);
1686: ASTORE(r2);
1687: ILOAD(b);
1688: IFNE(X_2);
1689: GOTO(S2_2_2b);
1690: LABEL(OC_2_2);
1691:
1692: // main subroutine handlers:
1693: TRYCATCH(T1, C1, C1);
1694: TRYCATCH(T1, OC, OC);
1695:
1696: // first instance of first sub try/catch handlers:
1697: TRYCATCH(L_1, C2_1, C2_1);
1698: TRYCATCH(OT_1, OC_1, OC); // note: reuses handler code from main
1699: // sub
1700:
1701: // second instance of first sub try/catch handlers:
1702: TRYCATCH(L_2, C2_2, C2_2);
1703: TRYCATCH(OT_2, OC_2, OC);
1704:
1705: // all 4 instances of second sub:
1706: TRYCATCH(OT_1_1, OC_1_1, OC);
1707: TRYCATCH(OT_1_2, OC_1_2, OC);
1708: TRYCATCH(OT_2_1, OC_2_1, OC);
1709: TRYCATCH(OT_2_2, OC_2_2, OC);
1710:
1711: END(1, 6);
1712: }
1713:
1714: assertEquals(exp, jsr);
1715: }
1716:
1717: /**
1718: * Tests a method which has line numbers and local variable declarations.
1719: *
1720: * <pre>
1721: * public void a() {
1722: * 1 int a = 0;
1723: * 2 try {
1724: * 3 a++;
1725: * 4 } finally {
1726: * 5 a--;
1727: * 6 }
1728: * }
1729: * LV "a" from 1 to 6
1730: * </pre>
1731: */
1732: public void testBasicLineNumberAndLocalVars() {
1733: {
1734: Label LM1 = new Label();
1735: Label L0 = new Label();
1736: Label L1 = new Label();
1737: Label L2 = new Label();
1738: Label L3 = new Label();
1739: Label L4 = new Label();
1740:
1741: setCurrent(jsr);
1742: LABEL(LM1);
1743: LINE(1, LM1);
1744: ICONST_0();
1745: ISTORE(1);
1746:
1747: /* L0: body of try block */
1748: LABEL(L0);
1749: LINE(3, L0);
1750: IINC(1, 1);
1751: GOTO(L1);
1752:
1753: /* L2: exception handler */
1754: LABEL(L2);
1755: ASTORE(3);
1756: JSR(L3);
1757: ALOAD(3);
1758: ATHROW();
1759:
1760: /* L3: subroutine */
1761: LABEL(L3);
1762: LINE(5, L3);
1763: ASTORE(2);
1764: IINC(1, -1);
1765: RET(2);
1766:
1767: /* L1: non-exceptional exit from try block */
1768: LABEL(L1);
1769: JSR(L3);
1770: LABEL(L4); // L4
1771: RETURN();
1772:
1773: TRYCATCH(L0, L2, L2);
1774: TRYCATCH(L1, L4, L2);
1775: LOCALVAR("a", "I", 1, LM1, L4);
1776:
1777: END(1, 4);
1778: }
1779:
1780: {
1781: Label LM1 = new Label();
1782: Label L0 = new Label();
1783: Label L1 = new Label();
1784: Label L2 = new Label();
1785: Label L3_1a = new Label();
1786: Label L3_1b = new Label();
1787: Label L3_1c = new Label();
1788: Label L3_2a = new Label();
1789: Label L3_2b = new Label();
1790: Label L3_2c = new Label();
1791: Label L4 = new Label();
1792:
1793: setCurrent(exp);
1794: LABEL(LM1);
1795: LINE(1, LM1);
1796: ICONST_0();
1797: ISTORE(1);
1798: // L0: try/catch block
1799: LABEL(L0);
1800: LINE(3, L0);
1801: IINC(1, 1);
1802: GOTO(L1);
1803:
1804: // L2: Exception handler:
1805: LABEL(L2);
1806: ASTORE(3);
1807: ACONST_NULL();
1808: GOTO(L3_1a);
1809: LABEL(L3_1b); // L3_1b;
1810: ALOAD(3);
1811: ATHROW();
1812:
1813: // L1: On non-exceptional exit, try block leads here:
1814: LABEL(L1);
1815: ACONST_NULL();
1816: GOTO(L3_2a);
1817: LABEL(L3_2b); // L3_2b
1818: LABEL(L4); // L4
1819: RETURN();
1820:
1821: // L3_1a: First instantiation of subroutine:
1822: LABEL(L3_1a);
1823: LINE(5, L3_1a);
1824: ASTORE(2);
1825: IINC(1, -1);
1826: GOTO(L3_1b);
1827: LABEL(L3_1c);
1828:
1829: // L3_2a: Second instantiation of subroutine:
1830: LABEL(L3_2a);
1831: LINE(5, L3_2a);
1832: ASTORE(2);
1833: IINC(1, -1);
1834: GOTO(L3_2b);
1835: LABEL(L3_2c);
1836:
1837: TRYCATCH(L0, L2, L2);
1838: TRYCATCH(L1, L4, L2);
1839: LOCALVAR("a", "I", 1, LM1, L4);
1840: LOCALVAR("a", "I", 1, L3_1a, L3_1c);
1841: LOCALVAR("a", "I", 1, L3_2a, L3_2c);
1842:
1843: END(1, 4);
1844: }
1845:
1846: assertEquals(exp, jsr);
1847: }
1848:
1849: public void assertEquals(final MethodNode exp,
1850: final MethodNode actual) {
1851: String textexp = getText(exp);
1852: String textact = getText(actual);
1853: System.err.println("Expected=" + textexp);
1854: System.err.println("Actual=" + textact);
1855: assertEquals(textexp, textact);
1856: }
1857:
1858: private String getText(final MethodNode mn) {
1859: TraceMethodVisitor tmv = new TraceMethodVisitor(null);
1860: mn.accept(tmv);
1861:
1862: StringBuffer sb = new StringBuffer();
1863: for (int i = 0; i < tmv.text.size(); i++) {
1864: sb.append(tmv.text.get(i));
1865: }
1866: return sb.toString();
1867: }
1868: }
|