1 30 package org.objectweb.asm; 31 32 import java.io.ByteArrayInputStream ; 33 import java.io.FileInputStream ; 34 import java.lang.reflect.Field ; 35 import java.util.HashMap ; 36 import java.util.HashSet ; 37 import java.util.Iterator ; 38 import java.util.Map ; 39 import java.util.Properties ; 40 import java.util.Set ; 41 import java.util.StringTokenizer ; 42 43 import junit.framework.TestCase; 44 45 import org.objectweb.asm.commons.EmptyVisitor; 46 47 52 public class ClassWriterComputeMaxsUnitTest extends TestCase { 53 54 private Field successors; 55 56 private Field successor; 57 58 private Field succ; 59 60 private Field next; 61 62 protected ClassWriter cw; 63 64 protected MethodVisitor mv; 65 66 private Label start; 67 68 protected void setUp() throws Exception { 69 Class lClass = Label.class; 70 Class 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 exception) { 77 String f = "src/org/objectweb/asm/optimizer/shrink.properties"; 78 Properties p = new Properties (); 79 p.load(new FileInputStream (f)); 80 String l = Type.getInternalName(lClass) + "."; 81 String 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 name, 200 final String desc, 201 final String signature, 202 final String [] 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 c = loader.defineClass("C", b); 224 c.newInstance(); 225 } catch (Throwable t) { 226 fail(t.getMessage()); 227 } 228 } 229 230 protected void assertGraph(final String graph) { 231 Map expected = new HashMap (); 232 Properties p = new Properties (); 233 try { 234 p.load(new ByteArrayInputStream (graph.getBytes())); 235 } catch (Exception e) { 236 fail(); 237 } 238 Iterator i = p.keySet().iterator(); 239 while (i.hasNext()) { 240 String key = (String ) i.next(); 241 String value = p.getProperty(key); 242 StringTokenizer st = new StringTokenizer (value, ","); 243 Set s = new HashSet (); 244 while (st.hasMoreTokens()) { 245 s.add(st.nextToken()); 246 } 247 expected.put(key, s); 248 } 249 250 Map actual = new HashMap (); 251 try { 252 Label l = start; 253 while (l != null) { 254 String key = "N" + l.getOffset(); 255 Set value = new HashSet (); 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 e) { 265 fail(); 266 } 267 268 assertEquals(expected, actual); 269 } 270 271 protected static class TestClassLoader extends ClassLoader { 272 273 public TestClassLoader() { 274 } 275 276 public Class defineClass(final String name, final byte[] b) { 277 return defineClass(name, b, 0, b.length); 278 } 279 } 280 281 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(); ISTORE(1); 305 306 307 LABEL(L0); IINC(1, 1); 309 GOTO(L1); 310 311 312 LABEL(L2); ASTORE(3); 314 JSR(L3); 315 ALOAD(3); ATHROW(); 317 318 319 LABEL(L3); ASTORE(2); 321 IINC(1, -1); 322 PUSH(); 323 PUSH(); 324 RET(2); 325 326 327 LABEL(L1); JSR(L3); 329 PUSH(); PUSH(); 331 LABEL(L4); 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 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(); ISTORE(1); 371 372 373 LABEL(L0); IINC(1, 1); 375 GOTO(L1); 376 377 378 LABEL(L2); ASTORE(3); 380 JSR(L3); 381 PUSH(); PUSH(); 383 ALOAD(3); 384 ATHROW(); 385 386 387 LABEL(L3); ASTORE(2); 389 PUSH(); 390 PUSH(); 391 ILOAD(1); 392 IFNE(L4); 393 IINC(1, 2); 394 GOTO(L5); 395 396 LABEL(L4); IINC(1, 3); 398 399 LABEL(L5); RET(2); 401 402 403 LABEL(L1); JSR(L3); 405 LABEL(L6); 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 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(); ISTORE(1); 446 447 LABEL(L0); IINC(1, 1); 450 JSR(L3); 451 GOTO(L1); 453 LABEL(L2); ASTORE(4); 456 JSR(L3); 457 ALOAD(4); ATHROW(); 459 460 LABEL(L3); ASTORE(2); 463 IINC(1, 2); 464 JSR(L4); 465 PUSH(); PUSH(); 467 RET(2); 468 469 LABEL(L5); ASTORE(5); 472 JSR(L4); 473 ALOAD(5); ATHROW(); 475 476 LABEL(L4); ASTORE(3); 479 PUSH(); 480 PUSH(); 481 IINC(1, 3); 482 RET(3); 483 484 LABEL(L1); 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 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(); ISTORE(1); 529 530 LABEL(L0); IINC(1, 1); 533 JSR(L1); 534 GOTO(L2); 536 LABEL(L3); ASTORE(2); 539 JSR(L1); 540 PUSH(); PUSH(); 542 ALOAD(2); 543 ATHROW(); 544 545 LABEL(L1); ASTORE(3); 548 IINC(1, 2); 549 GOTO(L4); 551 LABEL(L2); GOTO(L0); 554 555 LABEL(L4); 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 580 public void testSubroutineWithNoRet2() { 581 Label L0 = new Label(); 582 Label L1 = new Label(); 583 584 ACONST_NULL(); JSR(L0); 586 NOP(); LABEL(L0); ASTORE(0); 589 ASTORE(0); 590 RETURN(); 591 LABEL(L1); 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 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(); ISTORE(1); 631 632 LABEL(L5); ACONST_NULL(); 635 IFNONNULL(L4); 636 637 LABEL(L0); IINC(1, 1); 640 JSR(L1); 641 GOTO(L2); 643 LABEL(L3); ASTORE(2); 646 JSR(L1); 647 ALOAD(2); PUSH(); 649 PUSH(); 650 ATHROW(); 651 652 LABEL(L1); ASTORE(3); 655 IINC(1, 2); 656 GOTO(L4); 658 LABEL(L2); GOTO(L0); 661 662 LABEL(L4); 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 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 int b = 1; 711 int e1 = 2; 712 int e2 = 3; 713 int r1 = 4; 714 int r2 = 5; 715 716 ICONST_0(); ISTORE(1); 718 719 LABEL(T1); JSR(S1); 722 RETURN(); 724 LABEL(C1); ASTORE(e1); 727 JSR(S1); 728 PUSH(); PUSH(); 730 ALOAD(e1); 731 ATHROW(); 732 733 LABEL(S1); ASTORE(r1); 736 PUSH(); 737 PUSH(); 738 GOTO(W); 739 740 LABEL(L); JSR(S2); 743 RETURN(); 745 LABEL(C2); ASTORE(e2); 748 PUSH(); 749 PUSH(); 750 JSR(S2); 751 ALOAD(e2); ATHROW(); 753 754 LABEL(S2); ASTORE(r2); 757 ILOAD(b); 758 IFNE(X); 759 RET(r2); 760 761 LABEL(W); ILOAD(b); 764 IFNE(L); 766 LABEL(X); 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(); ISTORE(1); 787 JSR(L1); 788 RETURN(); 790 LABEL(L1); ASTORE(2); 792 JSR(L2); 793 GOTO(L3); 795 LABEL(L2); ASTORE(3); 797 ILOAD(1); 798 IFNE(L3); 799 RET(3); 800 801 LABEL(L3); 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 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(); ISTORE(1); 823 JSR(L1); 824 GOTO(L2); 826 LABEL(L1); ASTORE(2); 829 IINC(1, 1); 830 GOTO(L3); 831 832 LABEL(L2); IINC(1, 2); 835 GOTO(L4); 836 837 LABEL(L3); IINC(1, 4); 840 PUSH(); 841 PUSH(); 842 RET(2); 843 844 LABEL(L4); 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 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 int b = 1; 895 int e1 = 2; 896 int e2 = 3; 897 int r1 = 4; 898 int r2 = 5; 899 900 ICONST_0(); ISTORE(1); 902 903 LABEL(T1); JSR(S1); 906 RETURN(); 908 LABEL(C1); ASTORE(e1); 911 JSR(S1); 912 ALOAD(e1); ATHROW(); 914 915 LABEL(S1); ASTORE(r1); 918 GOTO(W); 919 920 LABEL(L); JSR(S2); 923 PUSH(); PUSH(); 925 RETURN(); 926 927 LABEL(C2); ASTORE(e2); 930 JSR(S2); 931 ALOAD(e2); ATHROW(); 933 934 LABEL(S2); ASTORE(r2); 937 ILOAD(b); 938 IFNE(X); 939 PUSH(); 940 PUSH(); 941 RET(r2); 942 943 LABEL(W); ILOAD(b); 946 IFNE(L); 948 LABEL(X); RET(r1); 951 952 LABEL(OC); 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 |