KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > asm > ClassWriterComputeMaxsUnitTest


1 /***
2  * ASM tests
3  * Copyright (c) 2002-2005 France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30 package org.objectweb.asm;
31
32 import java.io.ByteArrayInputStream JavaDoc;
33 import java.io.FileInputStream JavaDoc;
34 import java.lang.reflect.Field JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.HashSet JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.Map JavaDoc;
39 import java.util.Properties JavaDoc;
40 import java.util.Set JavaDoc;
41 import java.util.StringTokenizer JavaDoc;
42
43 import junit.framework.TestCase;
44
45 import org.objectweb.asm.commons.EmptyVisitor;
46
47 /**
48  * ClassWriter unit tests for COMPUTE_MAXS option with JSR instructions.
49  *
50  * @author Eric Bruneton
51  */

52 public class ClassWriterComputeMaxsUnitTest extends TestCase {
53
54     private Field JavaDoc successors;
55
56     private Field JavaDoc successor;
57
58     private Field JavaDoc succ;
59
60     private Field JavaDoc next;
61
62     protected ClassWriter cw;
63
64     protected MethodVisitor mv;
65
66     private Label start;
67
68     protected void setUp() throws Exception JavaDoc {
69         Class JavaDoc lClass = Label.class;
70         Class JavaDoc eClass = Edge.class;
71         try {
72             successors = lClass.getDeclaredField("successors");
73             successor = lClass.getDeclaredField("successor");
74             succ = eClass.getDeclaredField("successor");
75             next = eClass.getDeclaredField("next");
76         } catch (Exception JavaDoc exception) {
77             String JavaDoc f = "src/org/objectweb/asm/optimizer/shrink.properties";
78             Properties JavaDoc p = new Properties JavaDoc();
79             p.load(new FileInputStream JavaDoc(f));
80             String JavaDoc l = Type.getInternalName(lClass) + ".";
81             String JavaDoc e = Type.getInternalName(eClass) + ".";
82             successors = lClass.getDeclaredField(p.getProperty(l + "successors"));
83             successor = lClass.getDeclaredField(p.getProperty(l + "successor"));
84             succ = eClass.getDeclaredField(p.getProperty(e + "successor"));
85             next = eClass.getDeclaredField(p.getProperty(e + "next"));
86         }
87         cw = new ClassWriter(isComputeMaxs() ? ClassWriter.COMPUTE_MAXS : 0);
88         cw.visit(Opcodes.V1_1,
89                 Opcodes.ACC_PUBLIC,
90                 "C",
91                 null,
92                 "java/lang/Object",
93                 null);
94         mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
95         mv.visitCode();
96         mv.visitVarInsn(Opcodes.ALOAD, 0);
97         mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
98                 "java/lang/Object",
99                 "<init>",
100                 "()V");
101         mv.visitInsn(Opcodes.RETURN);
102         mv.visitMaxs(1, 1);
103         mv.visitEnd();
104         mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "m", "()V", null, null);
105         mv.visitCode();
106         start = new Label();
107         LABEL(start);
108     }
109
110     protected boolean isComputeMaxs() {
111         return true;
112     }
113     
114     private void NOP() {
115         mv.visitInsn(Opcodes.NOP);
116     }
117
118     private void PUSH() {
119         mv.visitInsn(Opcodes.ICONST_0);
120     }
121
122     private void ICONST_0() {
123         mv.visitInsn(Opcodes.ICONST_0);
124     }
125
126     private void ISTORE(final int var) {
127         mv.visitVarInsn(Opcodes.ISTORE, var);
128     }
129
130     private void ALOAD(final int var) {
131         mv.visitVarInsn(Opcodes.ALOAD, var);
132     }
133
134     private void ILOAD(final int var) {
135         mv.visitVarInsn(Opcodes.ILOAD, var);
136     }
137
138     private void ASTORE(final int var) {
139         mv.visitVarInsn(Opcodes.ASTORE, var);
140     }
141
142     private void RET(final int var) {
143         mv.visitVarInsn(Opcodes.RET, var);
144     }
145
146     private void ATHROW() {
147         mv.visitInsn(Opcodes.ATHROW);
148     }
149
150     private void ACONST_NULL() {
151         mv.visitInsn(Opcodes.ACONST_NULL);
152     }
153
154     private void RETURN() {
155         mv.visitInsn(Opcodes.RETURN);
156     }
157
158     private void LABEL(final Label l) {
159         mv.visitLabel(l);
160     }
161
162     private void IINC(final int var, final int amnt) {
163         mv.visitIincInsn(var, amnt);
164     }
165
166     private void GOTO(final Label l) {
167         mv.visitJumpInsn(Opcodes.GOTO, l);
168     }
169
170     private void JSR(final Label l) {
171         mv.visitJumpInsn(Opcodes.JSR, l);
172     }
173
174     private void IFNONNULL(final Label l) {
175         mv.visitJumpInsn(Opcodes.IFNONNULL, l);
176     }
177
178     private void IFNE(final Label l) {
179         mv.visitJumpInsn(Opcodes.IFNE, l);
180     }
181
182     private void TRYCATCH(
183         final Label start,
184         final Label end,
185         final Label handler)
186     {
187         mv.visitTryCatchBlock(start, end, handler, null);
188     }
189
190     protected void assertMaxs(final int maxStack, final int maxLocals) {
191         mv.visitMaxs(0, 0);
192         mv.visitEnd();
193         cw.visitEnd();
194         byte[] b = cw.toByteArray();
195         ClassReader cr = new ClassReader(b);
196         cr.accept(new EmptyVisitor() {
197             public MethodVisitor visitMethod(
198                 final int access,
199                 final String JavaDoc name,
200                 final String JavaDoc desc,
201                 final String JavaDoc signature,
202                 final String JavaDoc[] exceptions)
203             {
204                 if (name.equals("m")) {
205                     return new EmptyVisitor() {
206                         public void visitMaxs(
207                             final int realMaxStack,
208                             final int realMaxLocals)
209                         {
210                             assertEquals("maxStack", maxStack, realMaxStack);
211                             assertEquals("maxLocals", maxLocals, realMaxLocals);
212                         }
213                     };
214                 } else {
215                     return new EmptyVisitor();
216                 }
217             }
218         },
219                 0);
220
221         try {
222             TestClassLoader loader = new TestClassLoader();
223             Class JavaDoc c = loader.defineClass("C", b);
224             c.newInstance();
225         } catch (Throwable JavaDoc t) {
226             fail(t.getMessage());
227         }
228     }
229
230     protected void assertGraph(final String JavaDoc graph) {
231         Map JavaDoc expected = new HashMap JavaDoc();
232         Properties JavaDoc p = new Properties JavaDoc();
233         try {
234             p.load(new ByteArrayInputStream JavaDoc(graph.getBytes()));
235         } catch (Exception JavaDoc e) {
236             fail();
237         }
238         Iterator JavaDoc i = p.keySet().iterator();
239         while (i.hasNext()) {
240             String JavaDoc key = (String JavaDoc) i.next();
241             String JavaDoc value = p.getProperty(key);
242             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(value, ",");
243             Set JavaDoc s = new HashSet JavaDoc();
244             while (st.hasMoreTokens()) {
245                 s.add(st.nextToken());
246             }
247             expected.put(key, s);
248         }
249
250         Map JavaDoc actual = new HashMap JavaDoc();
251         try {
252             Label l = start;
253             while (l != null) {
254                 String JavaDoc key = "N" + l.getOffset();
255                 Set JavaDoc value = new HashSet JavaDoc();
256                 Edge e = (Edge) successors.get(l);
257                 while (e != null) {
258                     value.add("N" + ((Label) succ.get(e)).getOffset());
259                     e = (Edge) next.get(e);
260                 }
261                 actual.put(key, value);
262                 l = (Label) successor.get(l);
263             }
264         } catch (Exception JavaDoc e) {
265             fail();
266         }
267
268         assertEquals(expected, actual);
269     }
270
271     protected static class TestClassLoader extends ClassLoader JavaDoc {
272
273         public TestClassLoader() {
274         }
275
276         public Class JavaDoc defineClass(final String JavaDoc name, final byte[] b) {
277             return defineClass(name, b, 0, b.length);
278         }
279     }
280
281     /**
282      * Tests a method which has the most basic <code>try{}finally</code> form
283      * imaginable:
284      *
285      * <pre>
286      * public void a() {
287      * int a = 0;
288      * try {
289      * a++;
290      * } finally {
291      * a--;
292      * }
293      * }
294      * </pre>
295      */

296     public void testBasic() {
297         Label L0 = new Label();
298         Label L1 = new Label();
299         Label L2 = new Label();
300         Label L3 = new Label();
301         Label L4 = new Label();
302
303         ICONST_0(); // N0
304
ISTORE(1);
305
306         /* L0: body of try block */
307         LABEL(L0); // N2
308
IINC(1, 1);
309         GOTO(L1);
310
311         /* L2: exception handler */
312         LABEL(L2); // N8
313
ASTORE(3);
314         JSR(L3);
315         ALOAD(3); // N12
316
ATHROW();
317
318         /* L3: subroutine */
319         LABEL(L3); // N14
320
ASTORE(2);
321         IINC(1, -1);
322         PUSH();
323         PUSH();
324         RET(2);
325
326         /* L1: non-exceptional exit from try block */
327         LABEL(L1); // N22
328
JSR(L3);
329         PUSH(); // N25
330
PUSH();
331         LABEL(L4); // N27
332
RETURN();
333
334         TRYCATCH(L0, L2, L2);
335         TRYCATCH(L1, L4, L2);
336
337         assertMaxs(4, 4);
338         assertGraph("N0=N2\n" + "N2=N22,N8\n" + "N8=N14,N12\n" + "N12=\n"
339                 + "N14=N12,N25\n" + "N22=N14,N25,N8\n" + "N25=N27,N8\n"
340                 + "N27=\n");
341     }
342
343     /**
344      * Tests a method which has an if/else-if w/in the finally clause:
345      *
346      * <pre>
347      * public void a() {
348      * int a = 0;
349      * try {
350      * a++;
351      * } finally {
352      * if (a == 0)
353      * a+=2;
354      * else
355      * a+=3;
356      * }
357      * }
358      * </pre>
359      */

360     public void testIfElseInFinally() {
361         Label L0 = new Label();
362         Label L1 = new Label();
363         Label L2 = new Label();
364         Label L3 = new Label();
365         Label L4 = new Label();
366         Label L5 = new Label();
367         Label L6 = new Label();
368
369         ICONST_0(); // N0
370
ISTORE(1);
371
372         /* L0: body of try block */
373         LABEL(L0); // N2
374
IINC(1, 1);
375         GOTO(L1);
376
377         /* L2: exception handler */
378         LABEL(L2); // N8
379
ASTORE(3);
380         JSR(L3);
381         PUSH(); // N12
382
PUSH();
383         ALOAD(3);
384         ATHROW();
385
386         /* L3: subroutine */
387         LABEL(L3); // N16
388
ASTORE(2);
389         PUSH();
390         PUSH();
391         ILOAD(1);
392         IFNE(L4);
393         IINC(1, 2);
394         GOTO(L5);
395
396         LABEL(L4); // N29
397
IINC(1, 3);
398
399         LABEL(L5); // N32 common exit
400
RET(2);
401
402         /* L1: non-exceptional exit from try block */
403         LABEL(L1); // N34
404
JSR(L3);
405         LABEL(L6); // N37
406
RETURN();
407
408         TRYCATCH(L0, L2, L2);
409         TRYCATCH(L1, L6, L2);
410
411         assertMaxs(5, 4);
412         assertGraph("N0=N2\n" + "N2=N34,N8\n" + "N8=N16,N12\n" + "N12=\n"
413                 + "N16=N29,N32\n" + "N29=N32\n" + "N32=N37,N12\n"
414                 + "N34=N16,N37,N8\n" + "N37=\n");
415
416     }
417
418     /**
419      * Tests a simple nested finally:
420      *
421      * <pre>
422      * public void a1() {
423      * int a = 0;
424      * try {
425      * a += 1;
426      * } finally {
427      * try {
428      * a += 2;
429      * } finally {
430      * a += 3;
431      * }
432      * }
433      * }
434      * </pre>
435      */

436     public void testSimpleNestedFinally() {
437         Label L0 = new Label();
438         Label L1 = new Label();
439         Label L2 = new Label();
440         Label L3 = new Label();
441         Label L4 = new Label();
442         Label L5 = new Label();
443
444         ICONST_0(); // N0
445
ISTORE(1);
446
447         // L0: Body of try block:
448
LABEL(L0); // N2
449
IINC(1, 1);
450         JSR(L3);
451         GOTO(L1); // N8
452

453         // L2: First exception handler:
454
LABEL(L2); // N11
455
ASTORE(4);
456         JSR(L3);
457         ALOAD(4); // N16
458
ATHROW();
459
460         // L3: First subroutine:
461
LABEL(L3); // N19
462
ASTORE(2);
463         IINC(1, 2);
464         JSR(L4);
465         PUSH(); // N26
466
PUSH();
467         RET(2);
468
469         // L5: Second exception handler:
470
LABEL(L5); // N30
471
ASTORE(5);
472         JSR(L4);
473         ALOAD(5); // N35
474
ATHROW();
475
476         // L4: Second subroutine:
477
LABEL(L4); // N38
478
ASTORE(3);
479         PUSH();
480         PUSH();
481         IINC(1, 3);
482         RET(3);
483
484         // L1: On normal exit, try block jumps here:
485
LABEL(L1); // N46
486
RETURN();
487
488         TRYCATCH(L0, L2, L2);
489         TRYCATCH(L3, L5, L5);
490
491         assertMaxs(5, 6);
492         assertGraph("N0=N2\n" + "N2=N11,N19,N8\n" + "N8=N11,N46\n"
493                 + "N11=N19,N16\n" + "N16=\n" + "N19=N26,N30,N38\n"
494                 + "N26=N16,N30,N8\n" + "N30=N38,N35\n" + "N35=\n"
495                 + "N38=N26,N35\n" + "N46=\n");
496     }
497
498     /**
499      * This tests a subroutine which has no ret statement, but ends in a
500      * "return" instead.
501      *
502      * We structure this as a try/finally with a break in the finally. Because
503      * the while loop is infinite, it's clear from the byte code that the only
504      * path which reaches the RETURN instruction is through the subroutine.
505      *
506      * <pre>
507      * public void a1() {
508      * int a = 0;
509      * while (true) {
510      * try {
511      * a += 1;
512      * } finally {
513      * a += 2;
514      * break;
515      * }
516      * }
517      * }
518      * </pre>
519      */

520     public void testSubroutineWithNoRet() {
521         Label L0 = new Label();
522         Label L1 = new Label();
523         Label L2 = new Label();
524         Label L3 = new Label();
525         Label L4 = new Label();
526
527         ICONST_0(); // N0
528
ISTORE(1);
529
530         // L0: while loop header/try block
531
LABEL(L0); // N2
532
IINC(1, 1);
533         JSR(L1);
534         GOTO(L2); // N8
535

536         // L3: implicit catch block
537
LABEL(L3); // N11
538
ASTORE(2);
539         JSR(L1);
540         PUSH(); // N15
541
PUSH();
542         ALOAD(2);
543         ATHROW();
544
545         // L1: subroutine ...
546
LABEL(L1); // N19
547
ASTORE(3);
548         IINC(1, 2);
549         GOTO(L4); // ...not that it does not return!
550

551         // L2: end of the loop... goes back to the top!
552
LABEL(L2); // N26
553
GOTO(L0);
554
555         // L4:
556
LABEL(L4); // N29
557
RETURN();
558
559         TRYCATCH(L0, L3, L3);
560
561         assertMaxs(1, 4);
562         assertGraph("N0=N2\n" + "N2=N11,N19,N8\n" + "N8=N11,N26\n"
563                 + "N11=N19,N15\n" + "N15=\n" + "N19=N29\n" + "N26=N2\n"
564                 + "N29=\n");
565     }
566
567     /**
568      * This tests a subroutine which has no ret statement, but ends in a
569      * "return" instead.
570      *
571      * <pre>
572      * ACONST_NULL
573      * JSR L0
574      * L0:
575      * ASTORE 0
576      * ASTORE 0
577      * RETURN
578      * </pre>
579      */

580     public void testSubroutineWithNoRet2() {
581         Label L0 = new Label();
582         Label L1 = new Label();
583
584         ACONST_NULL(); // N0
585
JSR(L0);
586         NOP(); // N4
587
LABEL(L0); // N5
588
ASTORE(0);
589         ASTORE(0);
590         RETURN();
591         LABEL(L1); // N8
592
mv.visitLocalVariable("i", "I", null, L0, L1, 1);
593
594         assertMaxs(2, 2);
595         assertGraph("N0=N4,N5\n" + "N4=N5\n" + "N5=\n" + "N8=\n");
596     }
597
598     /**
599      * This tests a subroutine which has no ret statement, but instead exits
600      * implicitely by branching to code which is not part of the subroutine.
601      * (Sadly, this is legal)
602      *
603      * We structure this as a try/finally in a loop with a break in the finally.
604      * The loop is not trivially infinite, so the RETURN statement is reachable
605      * both from the JSR subroutine and from the main entry point.
606      *
607      * <pre>
608      * public void a1() {
609      * int a = 0;
610      * while (null == null) {
611      * try {
612      * a += 1;
613      * } finally {
614      * a += 2;
615      * break;
616      * }
617      * }
618      * }
619      * </pre>
620      */

621     public void testImplicitExit() {
622         Label L0 = new Label();
623         Label L1 = new Label();
624         Label L2 = new Label();
625         Label L3 = new Label();
626         Label L4 = new Label();
627         Label L5 = new Label();
628
629         ICONST_0(); // N0
630
ISTORE(1);
631
632         // L5: while loop header
633
LABEL(L5); // N2
634
ACONST_NULL();
635         IFNONNULL(L4);
636
637         // L0: try block
638
LABEL(L0); // N6
639
IINC(1, 1);
640         JSR(L1);
641         GOTO(L2); // N12
642

643         // L3: implicit catch block
644
LABEL(L3); // N15
645
ASTORE(2);
646         JSR(L1);
647         ALOAD(2); // N19
648
PUSH();
649         PUSH();
650         ATHROW();
651
652         // L1: subroutine ...
653
LABEL(L1); // N23
654
ASTORE(3);
655         IINC(1, 2);
656         GOTO(L4); // ...not that it does not return!
657

658         // L2: end of the loop... goes back to the top!
659
LABEL(L2); // N30
660
GOTO(L0);
661
662         // L4:
663
LABEL(L4); // N33
664
RETURN();
665
666         TRYCATCH(L0, L3, L3);
667
668         assertMaxs(1, 4);
669         assertGraph("N0=N2\n" + "N2=N6,N33\n" + "N6=N23,N12,N15\n"
670                 + "N12=N30,N15\n" + "N15=N23,N19\n" + "N19=\n" + "N23=N33\n"
671                 + "N30=N6\n" + "N33=\n");
672     }
673
674     /**
675      * Tests a nested try/finally with implicit exit from one subroutine to the
676      * other subroutine. Equivalent to the following java code:
677      *
678      * <pre>
679      * void m(boolean b) {
680      * try {
681      * return;
682      * } finally {
683      * while (b) {
684      * try {
685      * return;
686      * } finally {
687      * // NOTE --- this break avoids the second return above (weird)
688      * if (b) break;
689      * }
690      * }
691      * }
692      * }
693      * </pre>
694      *
695      * This example is from the paper, "Subroutine Inlining and Bytecode
696      * Abstraction to Simplify Static and Dynamic Analysis" by Cyrille Artho and
697      * Armin Biere.
698      */

699     public void testImplicitExitToAnotherSubroutine() {
700         Label T1 = new Label();
701         Label C1 = new Label();
702         Label S1 = new Label();
703         Label L = new Label();
704         Label C2 = new Label();
705         Label S2 = new Label();
706         Label W = new Label();
707         Label X = new Label();
708
709         // variable numbers:
710
int b = 1;
711         int e1 = 2;
712         int e2 = 3;
713         int r1 = 4;
714         int r2 = 5;
715
716         ICONST_0(); // N0
717
ISTORE(1);
718
719         // T1: first try:
720
LABEL(T1); // N2
721
JSR(S1);
722         RETURN(); // N5
723

724         // C1: exception handler for first try
725
LABEL(C1); // N6
726
ASTORE(e1);
727         JSR(S1);
728         PUSH(); // N10
729
PUSH();
730         ALOAD(e1);
731         ATHROW();
732
733         // S1: first finally handler
734
LABEL(S1); // N14
735
ASTORE(r1);
736         PUSH();
737         PUSH();
738         GOTO(W);
739
740         // L: body of while loop, also second try
741
LABEL(L); // N21
742
JSR(S2);
743         RETURN(); // N24
744

745         // C2: exception handler for second try
746
LABEL(C2); // N25
747
ASTORE(e2);
748         PUSH();
749         PUSH();
750         JSR(S2);
751         ALOAD(e2); // N31
752
ATHROW();
753
754         // S2: second finally handler
755
LABEL(S2); // N33
756
ASTORE(r2);
757         ILOAD(b);
758         IFNE(X);
759         RET(r2);
760
761         // W: test for the while loop
762
LABEL(W); // N41
763
ILOAD(b);
764         IFNE(L); // falls through to X
765

766         // X: exit from finally{} block
767
LABEL(X); // N45
768
RET(r1);
769
770         TRYCATCH(T1, C1, C1);
771         TRYCATCH(L, C2, C2);
772
773         assertMaxs(5, 6);
774         assertGraph("N0=N2\n" + "N2=N6,N5,N14\n" + "N5=N6\n" + "N6=N14,N10\n"
775                 + "N10=\n" + "N14=N41\n" + "N21=N24,N25,N33\n" + "N24=N25\n"
776                 + "N25=N31,N33\n" + "N31=\n" + "N33=N31,N45,N24\n"
777                 + "N41=N45,N21\n" + "N45=N5,N10\n");
778     }
779
780     public void testImplicitExitToAnotherSubroutine2() {
781         Label L1 = new Label();
782         Label L2 = new Label();
783         Label L3 = new Label();
784
785         ICONST_0(); // N0
786
ISTORE(1);
787         JSR(L1);
788         RETURN(); // N5
789

790         LABEL(L1); // N6
791
ASTORE(2);
792         JSR(L2);
793         GOTO(L3); // N10
794

795         LABEL(L2); // N13
796
ASTORE(3);
797         ILOAD(1);
798         IFNE(L3);
799         RET(3);
800
801         LABEL(L3); // N20
802
RET(2);
803
804         assertMaxs(1, 4);
805         assertGraph("N0=N6,N5\n" + "N5=\n" + "N6=N10,N13\n" + "N10=N20\n"
806                 + "N13=N20,N10\n" + "N20=N5\n");
807     }
808
809     /**
810      * This tests a simple subroutine where the control flow jumps back and
811      * forth between the subroutine and the caller.
812      *
813      * This would not normally be produced by a java compiler.
814      */

815     public void testInterleavedCode() {
816         Label L1 = new Label();
817         Label L2 = new Label();
818         Label L3 = new Label();
819         Label L4 = new Label();
820
821         ICONST_0(); // N0
822
ISTORE(1);
823         JSR(L1);
824         GOTO(L2); // N5
825

826         // L1: subroutine 1
827
LABEL(L1); // N8
828
ASTORE(2);
829         IINC(1, 1);
830         GOTO(L3);
831
832         // L2: second part of main subroutine
833
LABEL(L2); // N15
834
IINC(1, 2);
835         GOTO(L4);
836
837         // L3: second part of subroutine 1
838
LABEL(L3); // N21
839
IINC(1, 4);
840         PUSH();
841         PUSH();
842         RET(2);
843
844         // L4: third part of main subroutine
845
LABEL(L4); // N28
846
PUSH();
847         PUSH();
848         RETURN();
849
850         assertMaxs(4, 3);
851         assertGraph("N0=N5,N8\n" + "N5=N15\n" + "N8=N21\n" + "N15=N28\n"
852                 + "N21=N5\n" + "N28=\n");
853     }
854
855     /**
856      * Tests a nested try/finally with implicit exit from one subroutine to the
857      * other subroutine, and with a surrounding try/catch thrown in the mix.
858      * Equivalent to the following java code:
859      *
860      * <pre>
861      * void m(int b) {
862      * try {
863      * try {
864      * return;
865      * } finally {
866      * while (b) {
867      * try {
868      * return;
869      * } finally {
870      * // NOTE --- this break avoids the second return above (weird)
871      * if (b) break;
872      * }
873      * }
874      * }
875      * } catch (Exception e) {
876      * b += 3;
877      * return;
878      * }
879      * }
880      * </pre>
881      */

882     public void testImplicitExitInTryCatch() {
883         Label T1 = new Label();
884         Label C1 = new Label();
885         Label S1 = new Label();
886         Label L = new Label();
887         Label C2 = new Label();
888         Label S2 = new Label();
889         Label W = new Label();
890         Label X = new Label();
891         Label OC = new Label();
892
893         // variable numbers:
894
int b = 1;
895         int e1 = 2;
896         int e2 = 3;
897         int r1 = 4;
898         int r2 = 5;
899
900         ICONST_0(); // N0
901
ISTORE(1);
902
903         // T1: first try:
904
LABEL(T1); // N2
905
JSR(S1);
906         RETURN(); // N5
907

908         // C1: exception handler for first try
909
LABEL(C1); // N6
910
ASTORE(e1);
911         JSR(S1);
912         ALOAD(e1); // N10
913
ATHROW();
914
915         // S1: first finally handler
916
LABEL(S1); // N12
917
ASTORE(r1);
918         GOTO(W);
919
920         // L: body of while loop, also second try
921
LABEL(L); // N17
922
JSR(S2);
923         PUSH(); // N20
924
PUSH();
925         RETURN();
926
927         // C2: exception handler for second try
928
LABEL(C2); // N23
929
ASTORE(e2);
930         JSR(S2);
931         ALOAD(e2); // N27
932
ATHROW();
933
934         // S2: second finally handler
935
LABEL(S2); // N29
936
ASTORE(r2);
937         ILOAD(b);
938         IFNE(X);
939         PUSH();
940         PUSH();
941         RET(r2);
942
943         // W: test for the while loop
944
LABEL(W); // N39
945
ILOAD(b);
946         IFNE(L); // falls through to X
947

948         // X: exit from finally{} block
949
LABEL(X); // N43
950
RET(r1);
951
952         // OC: outermost catch
953
LABEL(OC); // N45
954
IINC(b, 3);
955         RETURN();
956
957         TRYCATCH(T1, C1, C1);
958         TRYCATCH(L, C2, C2);
959         TRYCATCH(T1, OC, OC);
960
961         assertMaxs(4, 6);
962         assertGraph("N0=N2\n" + "N2=N6,N45,N5,N12\n" + "N5=N6,N45\n"
963                 + "N6=N45,N12,N10\n" + "N10=N45\n" + "N12=N39,N45\n"
964                 + "N17=N23,N45,N20,N29\n" + "N20=N23,N45\n"
965                 + "N23=N45,N27,N29\n" + "N27=N45\n" + "N29=N43,N45,N20,N27\n"
966                 + "N39=N43,N45,N17\n" + "N43=N45,N5,N10\n" + "N45=\n");
967     }
968 }
969
Popular Tags