1 15 16 package javassist; 17 18 import javassist.bytecode.AccessFlag; 19 import javassist.bytecode.AttributeInfo; 20 import javassist.bytecode.BadBytecode; 21 import javassist.bytecode.Bytecode; 22 import javassist.bytecode.ClassFile; 23 import javassist.bytecode.CodeAttribute; 24 import javassist.bytecode.CodeIterator; 25 import javassist.bytecode.ConstPool; 26 import javassist.bytecode.Descriptor; 27 import javassist.bytecode.EnclosingMethodAttribute; 28 import javassist.bytecode.FieldInfo; 29 import javassist.bytecode.InnerClassesAttribute; 30 import javassist.bytecode.MethodInfo; 31 import javassist.compiler.AccessorMaker; 32 import javassist.compiler.CompileError; 33 import javassist.compiler.Javac; 34 import javassist.expr.ExprEditor; 35 36 import java.io.BufferedInputStream ; 37 import java.io.DataInputStream ; 38 import java.io.DataOutputStream ; 39 import java.io.IOException ; 40 import java.io.InputStream ; 41 import java.net.URL ; 42 import java.util.ArrayList ; 43 import java.util.Enumeration ; 44 import java.util.HashMap ; 45 import java.util.Hashtable ; 46 import java.util.List ; 47 48 51 class CtClassType extends CtClass { 52 ClassPool classPool; 53 boolean wasChanged; 54 private boolean wasFrozen; 55 boolean wasPruned; 56 boolean memberRemoved; 57 ClassFile classfile; 58 59 private CtMember fieldsCache; 60 private CtMember methodsCache; 61 private CtMember constructorsCache; 62 private CtConstructor classInitializerCache; 63 64 private AccessorMaker accessors; 65 66 private FieldInitLink fieldInitializers; 67 private Hashtable hiddenMethods; private int uniqueNumberSeed; 69 70 private boolean doPruning = false; 71 int getCounter; 72 private static int readCounter = 0; 73 private static final int READ_THRESHOLD = 100; 75 CtClassType(String name, ClassPool cp) { 76 super(name); 77 classPool = cp; 78 wasChanged = wasFrozen = wasPruned = memberRemoved = false; 79 classfile = null; 80 accessors = null; 81 fieldInitializers = null; 82 hiddenMethods = null; 83 uniqueNumberSeed = 0; 84 eraseCache(); 85 getCounter = 0; 86 } 87 88 CtClassType(InputStream ins, ClassPool cp) throws IOException { 89 this((String )null, cp); 90 classfile = new ClassFile(new DataInputStream (ins)); 91 qualifiedName = classfile.getName(); 92 } 93 94 protected void extendToString(StringBuffer buffer) { 95 if (wasChanged) 96 buffer.append("changed "); 97 98 if (wasFrozen) 99 buffer.append("frozen "); 100 101 if (wasPruned) 102 buffer.append("pruned "); 103 104 buffer.append(Modifier.toString(getModifiers())); 105 buffer.append(" class "); 106 buffer.append(getName()); 107 108 try { 109 CtClass ext = getSuperclass(); 110 if (ext != null) { 111 String name = ext.getName(); 112 if (!name.equals("java.lang.Object")) 113 buffer.append(" extends " + ext.getName()); 114 } 115 } 116 catch (NotFoundException e) { 117 buffer.append(" extends ??"); 118 } 119 120 try { 121 CtClass[] intf = getInterfaces(); 122 if (intf.length > 0) 123 buffer.append(" implements "); 124 125 for (int i = 0; i < intf.length; ++i) { 126 buffer.append(intf[i].getName()); 127 buffer.append(", "); 128 } 129 } 130 catch (NotFoundException e) { 131 buffer.append(" extends ??"); 132 } 133 134 CtMember field = getFieldsCache(); 135 buffer.append(" fields="); 136 while (field != null) { 137 buffer.append(field); 138 buffer.append(", "); 139 field = field.next; 140 } 141 142 CtMember c = getConstructorsCache(); 143 buffer.append(" constructors="); 144 while (c != null) { 145 buffer.append(c); 146 buffer.append(", "); 147 c = c.next; 148 } 149 150 CtMember m = getMethodsCache(); 151 buffer.append(" methods="); 152 while (m != null) { 153 buffer.append(m); 154 buffer.append(", "); 155 m = m.next; 156 } 157 } 158 159 protected void eraseCache() { 160 fieldsCache = null; 161 constructorsCache = null; 162 classInitializerCache = null; 163 methodsCache = null; 164 } 165 166 public AccessorMaker getAccessorMaker() { 167 if (accessors == null) 168 accessors = new AccessorMaker(this); 169 170 return accessors; 171 } 172 173 public ClassFile getClassFile2() { 174 if (classfile != null) 175 return classfile; 176 177 if (readCounter++ > READ_THRESHOLD) { 178 doCompaction(); 179 readCounter = 0; 180 } 181 182 InputStream fin = null; 183 try { 184 fin = classPool.openClassfile(getName()); 185 if (fin == null) 186 throw new NotFoundException(getName()); 187 188 fin = new BufferedInputStream (fin); 189 classfile = new ClassFile(new DataInputStream (fin)); 190 if (!classfile.getName().equals(qualifiedName)) 191 throw new RuntimeException (classfile.getName() + " in " 192 + qualifiedName.replace('.', '/') + ".java"); 193 194 return classfile; 195 } 196 catch (NotFoundException e) { 197 throw new RuntimeException (e.toString()); 198 } 199 catch (IOException e) { 200 throw new RuntimeException (e.toString()); 201 } 202 finally { 203 if (fin != null) 204 try { 205 fin.close(); 206 } 207 catch (IOException e) {} 208 } 209 } 210 211 215 void incGetCounter() { ++getCounter; } 216 217 private void doCompaction() { 218 Enumeration e = classPool.classes.elements(); 219 while (e.hasMoreElements()) { 220 Object obj = e.nextElement(); 221 if (obj instanceof CtClassType) { 222 CtClassType cct = (CtClassType)obj; 223 if (cct.getCounter < 2 && !cct.isModified()) { 224 cct.eraseCache(); 225 cct.classfile = null; 226 } 227 228 cct.getCounter = 0; 229 } 230 } 231 } 232 233 public ClassPool getClassPool() { return classPool; } 234 235 void setClassPool(ClassPool cp) { classPool = cp; } 236 237 public URL getURL() throws NotFoundException { 238 URL url = classPool.find(getName()); 239 if (url == null) 240 throw new NotFoundException(getName()); 241 else 242 return url; 243 } 244 245 public boolean isModified() { return wasChanged; } 246 247 public boolean isFrozen() { return wasFrozen; } 248 249 void freeze() { wasFrozen = true; } 250 251 void checkModify() throws RuntimeException { 252 super.checkModify(); 253 wasChanged = true; 254 } 255 256 public void defrost() { 257 checkPruned("defrost"); 258 wasFrozen = false; 259 } 260 261 public boolean subtypeOf(CtClass clazz) throws NotFoundException { 262 int i; 263 String cname = clazz.getName(); 264 if (this == clazz || getName().equals(cname)) 265 return true; 266 267 ClassFile file = getClassFile2(); 268 String supername = file.getSuperclass(); 269 if (supername != null && supername.equals(cname)) 270 return true; 271 272 String [] ifs = file.getInterfaces(); 273 int num = ifs.length; 274 for (i = 0; i < num; ++i) 275 if (ifs[i].equals(cname)) 276 return true; 277 278 if (supername != null && classPool.get(supername).subtypeOf(clazz)) 279 return true; 280 281 for (i = 0; i < num; ++i) 282 if (classPool.get(ifs[i]).subtypeOf(clazz)) 283 return true; 284 285 return false; 286 } 287 288 public void setName(String name) throws RuntimeException { 289 String oldname = getName(); 290 if (name.equals(oldname)) 291 return; 292 293 classPool.checkNotFrozen(name); 295 ClassFile cf = getClassFile2(); 296 super.setName(name); 297 cf.setName(name); 298 eraseCache(); 299 classPool.classNameChanged(oldname, this); 300 } 301 302 public void replaceClassName(ClassMap classnames) 303 throws RuntimeException 304 { 305 String oldClassName = getName(); 306 String newClassName 307 = (String )classnames.get(Descriptor.toJvmName(oldClassName)); 308 if (newClassName != null) { 309 newClassName = Descriptor.toJavaName(newClassName); 310 classPool.checkNotFrozen(newClassName); 312 } 313 314 super.replaceClassName(classnames); 315 ClassFile cf = getClassFile2(); 316 cf.renameClass(classnames); 317 eraseCache(); 318 319 if (newClassName != null) { 320 super.setName(newClassName); 321 classPool.classNameChanged(oldClassName, this); 322 } 323 } 324 325 public void replaceClassName(String oldname, String newname) 326 throws RuntimeException 327 { 328 String thisname = getName(); 329 if (thisname.equals(oldname)) 330 setName(newname); 331 else { 332 super.replaceClassName(oldname, newname); 333 getClassFile2().renameClass(oldname, newname); 334 eraseCache(); 335 } 336 } 337 338 public boolean isInterface() { 339 return Modifier.isInterface(getModifiers()); 340 } 341 342 public int getModifiers() { 343 int acc = getClassFile2().getAccessFlags(); 344 acc = AccessFlag.clear(acc, AccessFlag.SUPER); 345 return AccessFlag.toModifier(acc); 346 } 347 348 public void setModifiers(int mod) { 349 checkModify(); 350 int acc = AccessFlag.of(mod) | AccessFlag.SUPER; 351 getClassFile2().setAccessFlags(acc); 352 } 353 354 public boolean subclassOf(CtClass superclass) { 355 if (superclass == null) 356 return false; 357 358 String superName = superclass.getName(); 359 CtClass curr = this; 360 try { 361 while (curr != null) { 362 if (curr.getName().equals(superName)) 363 return true; 364 365 curr = curr.getSuperclass(); 366 } 367 } 368 catch (Exception ignored) {} 369 return false; 370 } 371 372 public CtClass getSuperclass() throws NotFoundException { 373 String supername = getClassFile2().getSuperclass(); 374 if (supername == null) 375 return null; 376 else 377 return classPool.get(supername); 378 } 379 380 public void setSuperclass(CtClass clazz) throws CannotCompileException { 381 checkModify(); 382 if (isInterface()) 383 addInterface(clazz); 384 else 385 getClassFile2().setSuperclass(clazz.getName()); 386 } 387 388 public CtClass[] getInterfaces() throws NotFoundException { 389 String [] ifs = getClassFile2().getInterfaces(); 390 int num = ifs.length; 391 CtClass[] ifc = new CtClass[num]; 392 for (int i = 0; i < num; ++i) 393 ifc[i] = classPool.get(ifs[i]); 394 395 return ifc; 396 } 397 398 public void setInterfaces(CtClass[] list) { 399 checkModify(); 400 String [] ifs; 401 if (list == null) 402 ifs = new String [0]; 403 else { 404 int num = list.length; 405 ifs = new String [num]; 406 for (int i = 0; i < num; ++i) 407 ifs[i] = list[i].getName(); 408 } 409 410 getClassFile2().setInterfaces(ifs); 411 } 412 413 public void addInterface(CtClass anInterface) { 414 checkModify(); 415 if (anInterface != null) 416 getClassFile2().addInterface(anInterface.getName()); 417 } 418 419 public CtClass getDeclaringClass() throws NotFoundException { 420 ClassFile cf = getClassFile2(); 421 InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute( 422 InnerClassesAttribute.tag); 423 if (ica == null) 424 return null; 425 426 String name = getName(); 427 int n = ica.tableLength(); 428 for (int i = 0; i < n; ++i) 429 if (name.equals(ica.innerClass(i))) { 430 String outName = ica.outerClass(i); 431 if (outName != null) 432 return classPool.get(outName); 433 } 434 435 return null; 436 } 437 438 public CtClass getEnclosingClass() throws NotFoundException { 439 CtClass enc = getDeclaringClass(); 440 if (enc == null) { 441 ClassFile cf = getClassFile2(); 442 EnclosingMethodAttribute ema 443 = (EnclosingMethodAttribute)cf.getAttribute( 444 EnclosingMethodAttribute.tag); 445 if (ema != null) 446 enc = classPool.get(ema.className()); 447 } 448 449 return enc; 450 } 451 452 public CtClass makeNestedClass(String name, boolean isStatic) { 453 if (!isStatic) 454 throw new RuntimeException ( 455 "sorry, only nested static class is supported"); 456 457 checkModify(); 458 CtClass c = classPool.makeNestedClass(getName() + "$" + name); 459 ClassFile cf = getClassFile2(); 460 InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute( 461 InnerClassesAttribute.tag); 462 if (ica == null) { 463 ica = new InnerClassesAttribute(cf.getConstPool()); 464 cf.addAttribute(ica); 465 } 466 467 ica.append(c.getName(), this.getName(), name, AccessFlag.STATIC); 468 ClassFile cf2 = c.getClassFile2(); 469 cf2.addAttribute(ica.copy(cf2.getConstPool(), null)); 470 return c; 471 } 472 473 public CtField[] getFields() { 474 ArrayList alist = new ArrayList (); 475 getFields(alist, this); 476 return (CtField[])alist.toArray(new CtField[alist.size()]); 477 } 478 479 private static void getFields(ArrayList alist, CtClass cc) { 480 int i, num; 481 if (cc == null) 482 return; 483 484 try { 485 getFields(alist, cc.getSuperclass()); 486 } 487 catch (NotFoundException e) {} 488 489 try { 490 CtClass[] ifs = cc.getInterfaces(); 491 num = ifs.length; 492 for (i = 0; i < num; ++i) 493 getFields(alist, ifs[i]); 494 } 495 catch (NotFoundException e) {} 496 497 CtMember cf = ((CtClassType)cc).getFieldsCache(); 498 while (cf != null) { 499 if (Modifier.isPublic(cf.getModifiers())) 500 alist.add(cf); 501 502 cf = cf.next; 503 } 504 } 505 506 public CtField getField(String name) throws NotFoundException { 507 CtField f = getField2(name); 508 if (f == null) 509 throw new NotFoundException("field: " + name + " in " + getName()); 510 else 511 return f; 512 } 513 514 CtField getField2(String name) { 515 CtField df = getDeclaredField2(name); 516 if (df != null) 517 return df; 518 519 try { 520 CtClass[] ifs = getInterfaces(); 521 int num = ifs.length; 522 for (int i = 0; i < num; ++i) { 523 CtField f = ifs[i].getField2(name); 524 if (f != null) 525 return f; 526 } 527 528 CtClass s = getSuperclass(); 529 if (s != null) 530 return s.getField2(name); 531 } 532 catch (NotFoundException e) {} 533 return null; 534 } 535 536 public CtField[] getDeclaredFields() { 537 CtMember cf = getFieldsCache(); 538 int num = CtField.count(cf); 539 CtField[] cfs = new CtField[num]; 540 int i = 0; 541 while (cf != null) { 542 cfs[i++] = (CtField)cf; 543 cf = cf.next; 544 } 545 546 return cfs; 547 } 548 549 protected CtMember getFieldsCache() { 550 if (fieldsCache == null) { 551 List list = getClassFile2().getFields(); 552 int n = list.size(); 553 for (int i = 0; i < n; ++i) { 554 FieldInfo finfo = (FieldInfo)list.get(i); 555 fieldsCache = CtMember.append(fieldsCache, 556 new CtField(finfo, this)); 557 } 558 } 559 560 return fieldsCache; 561 } 562 563 public CtField getDeclaredField(String name) throws NotFoundException { 564 CtField f = getDeclaredField2(name); 565 if (f == null) 566 throw new NotFoundException("field: " + name + " in " + getName()); 567 else 568 return f; 569 } 570 571 private CtField getDeclaredField2(String name) { 572 CtMember cf = getFieldsCache(); 573 while (cf != null) { 574 if (cf.getName().equals(name)) 575 return (CtField)cf; 576 577 cf = cf.next; 578 } 579 580 return null; 581 } 582 583 public CtBehavior[] getDeclaredBehaviors() { 584 CtMember cc = getConstructorsCache(); 585 CtMember cm = getMethodsCache(); 586 int num = CtMember.count(cm) + CtMember.count(cc); 587 CtBehavior[] cb = new CtBehavior[num]; 588 int i = 0; 589 while (cc != null) { 590 cb[i++] = (CtBehavior)cc; 591 cc = cc.next; 592 } 593 594 while (cm != null) { 595 cb[i++] = (CtBehavior)cm; 596 cm = cm.next; 597 } 598 599 return cb; 600 } 601 602 public CtConstructor[] getConstructors() { 603 CtConstructor[] cons = getDeclaredConstructors(); 604 if (cons.length == 0) 605 return cons; 606 607 int n = 0; 608 int i = cons.length; 609 while (--i >= 0) 610 if (Modifier.isPublic(cons[i].getModifiers())) 611 ++n; 612 613 CtConstructor[] result = new CtConstructor[n]; 614 n = 0; 615 i = cons.length; 616 while (--i >= 0) { 617 CtConstructor c = cons[i]; 618 if (Modifier.isPublic(c.getModifiers())) 619 result[n++] = c; 620 } 621 622 return result; 623 } 624 625 public CtConstructor getConstructor(String desc) 626 throws NotFoundException 627 { 628 CtConstructor cc = (CtConstructor)getConstructorsCache(); 629 while (cc != null) { 630 if (cc.getMethodInfo2().getDescriptor().equals(desc)) 631 return cc; 632 633 cc = (CtConstructor)cc.next; 634 } 635 636 return super.getConstructor(desc); 637 } 638 639 public CtConstructor[] getDeclaredConstructors() { 640 CtMember cc = getConstructorsCache(); 641 int num = CtMember.count(cc); 642 CtConstructor[] ccs = new CtConstructor[num]; 643 int i = 0; 644 while (cc != null) { 645 ccs[i++] = (CtConstructor)cc; 646 cc = cc.next; 647 } 648 649 return ccs; 650 } 651 652 protected CtMember getConstructorsCache() { 653 if (constructorsCache == null) { 654 List list = getClassFile2().getMethods(); 655 int n = list.size(); 656 for (int i = 0; i < n; ++i) { 657 MethodInfo minfo = (MethodInfo)list.get(i); 658 if (minfo.isConstructor()) 659 constructorsCache 660 = CtMember.append(constructorsCache, 661 new CtConstructor(minfo, this)); 662 } 663 } 664 665 return constructorsCache; 666 } 667 668 public CtConstructor getClassInitializer() { 669 if (classInitializerCache == null) { 670 MethodInfo minfo = getClassFile2().getStaticInitializer(); 671 if (minfo != null) 672 classInitializerCache = new CtConstructor(minfo, this); 673 } 674 675 return classInitializerCache; 676 } 677 678 public CtMethod[] getMethods() { 679 HashMap h = new HashMap (); 680 getMethods0(h, this); 681 return (CtMethod[])h.values().toArray(new CtMethod[0]); 682 } 683 684 private static void getMethods0(HashMap h, CtClass cc) { 685 try { 686 CtClass[] ifs = cc.getInterfaces(); 687 int size = ifs.length; 688 for (int i = 0; i < size; ++i) 689 getMethods0(h, ifs[i]); 690 } 691 catch (NotFoundException e) {} 692 693 try { 694 CtClass s = cc.getSuperclass(); 695 if (s != null) 696 getMethods0(h, s); 697 } 698 catch (NotFoundException e) {} 699 700 if (cc instanceof CtClassType) { 701 CtMember cm = ((CtClassType)cc).getMethodsCache(); 702 while (cm != null) { 703 if (Modifier.isPublic(cm.getModifiers())) 704 h.put(((CtMethod)cm).getStringRep(), cm); 705 706 cm = cm.next; 707 } 708 } 709 } 710 711 public CtMethod getMethod(String name, String desc) 712 throws NotFoundException 713 { 714 CtMethod m = getMethod0(this, name, desc); 715 if (m != null) 716 return m; 717 else 718 throw new NotFoundException(name + "(..) is not found in " 719 + getName()); 720 } 721 722 private static CtMethod getMethod0(CtClass cc, 723 String name, String desc) { 724 if (cc instanceof CtClassType) { 725 CtMethod cm = (CtMethod)((CtClassType)cc).getMethodsCache(); 726 while (cm != null) { 727 if (cm.getName().equals(name) 728 && cm.getMethodInfo2().getDescriptor().equals(desc)) 729 return cm; 730 731 cm = (CtMethod)cm.next; 732 } 733 } 734 735 try { 736 CtClass s = cc.getSuperclass(); 737 if (s != null) { 738 CtMethod m = getMethod0(s, name, desc); 739 if (m != null) 740 return m; 741 } 742 } 743 catch (NotFoundException e) {} 744 745 try { 746 CtClass[] ifs = cc.getInterfaces(); 747 int size = ifs.length; 748 for (int i = 0; i < size; ++i) { 749 CtMethod m = getMethod0(ifs[i], name, desc); 750 if (m != null) 751 return m; 752 } 753 } 754 catch (NotFoundException e) {} 755 return null; 756 } 757 758 public CtMethod[] getDeclaredMethods() { 759 CtMember cm = getMethodsCache(); 760 int num = CtMember.count(cm); 761 CtMethod[] cms = new CtMethod[num]; 762 int i = 0; 763 while (cm != null) { 764 cms[i++] = (CtMethod)cm; 765 cm = cm.next; 766 } 767 768 return cms; 769 } 770 771 public CtMethod getDeclaredMethod(String name) throws NotFoundException { 772 CtMember m = getMethodsCache(); 773 while (m != null) { 774 if (m.getName().equals(name)) 775 return (CtMethod)m; 776 777 m = m.next; 778 } 779 780 throw new NotFoundException(name + "(..) is not found in " 781 + getName()); 782 } 783 784 public CtMethod getDeclaredMethod(String name, CtClass[] params) 785 throws NotFoundException 786 { 787 String desc = Descriptor.ofParameters(params); 788 CtMethod m = (CtMethod)getMethodsCache(); 789 while (m != null) { 790 if (m.getName().equals(name) 791 && m.getMethodInfo2().getDescriptor().startsWith(desc)) 792 return m; 793 794 m = (CtMethod)m.next; 795 } 796 797 throw new NotFoundException(name + "(..) is not found in " 798 + getName()); 799 } 800 801 protected CtMember getMethodsCache() { 802 if (methodsCache == null) { 803 List list = getClassFile2().getMethods(); 804 int n = list.size(); 805 for (int i = 0; i < n; ++i) { 806 MethodInfo minfo = (MethodInfo)list.get(i); 807 if (minfo.isMethod()) 808 methodsCache = CtMember.append(methodsCache, 809 new CtMethod(minfo, this)); 810 } 811 } 812 813 return methodsCache; 814 } 815 816 public void addField(CtField f, String init) 817 throws CannotCompileException 818 { 819 addField(f, CtField.Initializer.byExpr(init)); 820 } 821 822 public void addField(CtField f, CtField.Initializer init) 823 throws CannotCompileException 824 { 825 checkModify(); 826 if (f.getDeclaringClass() != this) 827 throw new CannotCompileException("cannot add"); 828 829 if (init == null) 830 init = f.getInit(); 831 832 getFieldsCache(); 833 fieldsCache = CtField.append(fieldsCache, f); 834 getClassFile2().addField(f.getFieldInfo2()); 835 836 if (init != null) { 837 FieldInitLink fil = new FieldInitLink(f, init); 838 FieldInitLink link = fieldInitializers; 839 if (link == null) 840 fieldInitializers = fil; 841 else { 842 while (link.next != null) 843 link = link.next; 844 845 link.next = fil; 846 } 847 } 848 } 849 850 public void removeField(CtField f) throws NotFoundException { 851 checkModify(); 852 FieldInfo fi = f.getFieldInfo2(); 853 ClassFile cf = getClassFile2(); 854 if (cf.getFields().remove(fi)) { 855 fieldsCache = CtMember.remove(fieldsCache, f); 856 memberRemoved = true; 857 } 858 else 859 throw new NotFoundException(f.toString()); 860 } 861 862 public CtConstructor makeClassInitializer() 863 throws CannotCompileException 864 { 865 CtConstructor clinit = getClassInitializer(); 866 if (clinit != null) 867 return clinit; 868 869 checkModify(); 870 ClassFile cf = getClassFile2(); 871 Bytecode code = new Bytecode(cf.getConstPool(), 0, 0); 872 modifyClassConstructor(cf, code, 0, 0); 873 return getClassInitializer(); 874 } 875 876 public void addConstructor(CtConstructor c) 877 throws CannotCompileException 878 { 879 checkModify(); 880 if (c.getDeclaringClass() != this) 881 throw new CannotCompileException("cannot add"); 882 883 getConstructorsCache(); 884 constructorsCache = (CtConstructor)CtMember.append(constructorsCache, c); 885 getClassFile2().addMethod(c.getMethodInfo2()); 886 } 887 888 public void removeConstructor(CtConstructor m) throws NotFoundException { 889 checkModify(); 890 MethodInfo mi = m.getMethodInfo2(); 891 ClassFile cf = getClassFile2(); 892 if (cf.getMethods().remove(mi)) { 893 constructorsCache = CtMember.remove(constructorsCache, m); 894 memberRemoved = true; 895 } 896 else 897 throw new NotFoundException(m.toString()); 898 } 899 900 public void addMethod(CtMethod m) throws CannotCompileException { 901 checkModify(); 902 if (m.getDeclaringClass() != this) 903 throw new CannotCompileException("cannot add"); 904 905 getMethodsCache(); 906 methodsCache = CtMember.append(methodsCache, m); 907 getClassFile2().addMethod(m.getMethodInfo2()); 908 if ((m.getModifiers() & Modifier.ABSTRACT) != 0) 909 setModifiers(getModifiers() | Modifier.ABSTRACT); 910 } 911 912 public void removeMethod(CtMethod m) throws NotFoundException { 913 checkModify(); 914 MethodInfo mi = m.getMethodInfo2(); 915 ClassFile cf = getClassFile2(); 916 if (cf.getMethods().remove(mi)) { 917 methodsCache = CtMember.remove(methodsCache, m); 918 memberRemoved = true; 919 } 920 else 921 throw new NotFoundException(m.toString()); 922 } 923 924 public byte[] getAttribute(String name) { 925 AttributeInfo ai = getClassFile2().getAttribute(name); 926 if (ai == null) 927 return null; 928 else 929 return ai.get(); 930 } 931 932 public void setAttribute(String name, byte[] data) { 933 checkModify(); 934 ClassFile cf = getClassFile2(); 935 cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data)); 936 } 937 938 public void instrument(CodeConverter converter) 939 throws CannotCompileException 940 { 941 checkModify(); 942 ClassFile cf = getClassFile2(); 943 ConstPool cp = cf.getConstPool(); 944 List list = cf.getMethods(); 945 int n = list.size(); 946 for (int i = 0; i < n; ++i) { 947 MethodInfo minfo = (MethodInfo)list.get(i); 948 converter.doit(this, minfo, cp); 949 } 950 } 951 952 public void instrument(ExprEditor editor) 953 throws CannotCompileException 954 { 955 checkModify(); 956 ClassFile cf = getClassFile2(); 957 List list = cf.getMethods(); 958 int n = list.size(); 959 for (int i = 0; i < n; ++i) { 960 MethodInfo minfo = (MethodInfo)list.get(i); 961 editor.doit(this, minfo); 962 } 963 } 964 965 public void toBytecode(DataOutputStream out) 966 throws CannotCompileException, IOException 967 { 968 try { 969 if (isModified()) { 970 checkPruned("toBytecode"); 971 ClassFile cf = getClassFile2(); 972 if (memberRemoved) { 973 cf.compact(); 974 memberRemoved = false; 975 } 976 977 modifyClassConstructor(cf); 978 modifyConstructors(cf); 979 cf.write(out); 980 out.flush(); 981 fieldInitializers = null; 982 if (doPruning) { 983 cf.prune(); 985 wasPruned = true; 986 } 987 } 988 else { 989 classPool.writeClassfile(getName(), out); 990 eraseCache(); 992 classfile = null; 993 } 994 995 wasFrozen = true; 996 } 997 catch (NotFoundException e) { 998 throw new CannotCompileException(e); 999 } 1000 catch (IOException e) { 1001 throw new CannotCompileException(e); 1002 } 1003 } 1004 1005 private void checkPruned(String method) { 1006 if (wasPruned) 1007 throw new RuntimeException (method + "(): " + getName() 1008 + " was pruned."); 1009 } 1010 1011 public void stopPruning(boolean stop) { 1012 doPruning = !stop; 1013 } 1014 1015 private void modifyClassConstructor(ClassFile cf) 1016 throws CannotCompileException, NotFoundException 1017 { 1018 if (fieldInitializers == null) 1019 return; 1020 1021 Bytecode code = new Bytecode(cf.getConstPool(), 0, 0); 1022 Javac jv = new Javac(code, this); 1023 int stacksize = 0; 1024 boolean doInit = false; 1025 for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) { 1026 CtField f = fi.field; 1027 if (Modifier.isStatic(f.getModifiers())) { 1028 doInit = true; 1029 int s = fi.init.compileIfStatic(f.getType(), f.getName(), 1030 code, jv); 1031 if (stacksize < s) 1032 stacksize = s; 1033 } 1034 } 1035 1036 if (doInit) modifyClassConstructor(cf, code, stacksize, 0); 1038 } 1039 1040 private void modifyClassConstructor(ClassFile cf, Bytecode code, 1041 int stacksize, int localsize) 1042 throws CannotCompileException 1043 { 1044 MethodInfo m = cf.getStaticInitializer(); 1045 if (m == null) { 1046 code.add(Bytecode.RETURN); 1047 code.setMaxStack(stacksize); 1048 code.setMaxLocals(localsize); 1049 m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V"); 1050 m.setAccessFlags(AccessFlag.STATIC); 1051 m.setCodeAttribute(code.toCodeAttribute()); 1052 cf.addMethod(m); 1053 } 1054 else { 1055 CodeAttribute codeAttr = m.getCodeAttribute(); 1056 if (codeAttr == null) 1057 throw new CannotCompileException("empty <clinit>"); 1058 1059 try { 1060 CodeIterator it = codeAttr.iterator(); 1061 int pos = it.insertEx(code.get()); 1062 it.insert(code.getExceptionTable(), pos); 1063 int maxstack = codeAttr.getMaxStack(); 1064 if (maxstack < stacksize) 1065 codeAttr.setMaxStack(stacksize); 1066 1067 int maxlocals = codeAttr.getMaxLocals(); 1068 if (maxlocals < localsize) 1069 codeAttr.setMaxLocals(localsize); 1070 } 1071 catch (BadBytecode e) { 1072 throw new CannotCompileException(e); 1073 } 1074 } 1075 } 1076 1077 private void modifyConstructors(ClassFile cf) 1078 throws CannotCompileException, NotFoundException 1079 { 1080 if (fieldInitializers == null) 1081 return; 1082 1083 ConstPool cp = cf.getConstPool(); 1084 List list = cf.getMethods(); 1085 int n = list.size(); 1086 for (int i = 0; i < n; ++i) { 1087 MethodInfo minfo = (MethodInfo)list.get(i); 1088 if (minfo.isConstructor()) { 1089 CodeAttribute codeAttr = minfo.getCodeAttribute(); 1090 if (codeAttr != null) 1091 try { 1092 Bytecode init = new Bytecode(cp, 0, 1093 codeAttr.getMaxLocals()); 1094 CtClass[] params 1095 = Descriptor.getParameterTypes( 1096 minfo.getDescriptor(), 1097 classPool); 1098 int stacksize = makeFieldInitializer(init, params); 1099 insertAuxInitializer(codeAttr, init, stacksize); 1100 } 1101 catch (BadBytecode e) { 1102 throw new CannotCompileException(e); 1103 } 1104 } 1105 } 1106 } 1107 1108 private static void insertAuxInitializer(CodeAttribute codeAttr, 1109 Bytecode initializer, 1110 int stacksize) 1111 throws BadBytecode 1112 { 1113 CodeIterator it = codeAttr.iterator(); 1114 int index = it.skipSuperConstructor(); 1115 if (index < 0) { 1116 index = it.skipThisConstructor(); 1117 if (index >= 0) 1118 return; 1120 } 1122 1123 int pos = it.insertEx(initializer.get()); 1124 it.insert(initializer.getExceptionTable(), pos); 1125 int maxstack = codeAttr.getMaxStack(); 1126 if (maxstack < stacksize) 1127 codeAttr.setMaxStack(stacksize); 1128 } 1129 1130 private int makeFieldInitializer(Bytecode code, CtClass[] parameters) 1131 throws CannotCompileException, NotFoundException 1132 { 1133 int stacksize = 0; 1134 Javac jv = new Javac(code, this); 1135 try { 1136 jv.recordParams(parameters, false); 1137 } 1138 catch (CompileError e) { 1139 throw new CannotCompileException(e); 1140 } 1141 1142 for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) { 1143 CtField f = fi.field; 1144 if (!Modifier.isStatic(f.getModifiers())) { 1145 int s = fi.init.compile(f.getType(), f.getName(), code, 1146 parameters, jv); 1147 if (stacksize < s) 1148 stacksize = s; 1149 } 1150 } 1151 1152 return stacksize; 1153 } 1154 1155 1157 Hashtable getHiddenMethods() { 1158 if (hiddenMethods == null) 1159 hiddenMethods = new Hashtable (); 1160 1161 return hiddenMethods; 1162 } 1163 1164 int getUniqueNumber() { return uniqueNumberSeed++; } 1165} 1166 1167class FieldInitLink { 1168 FieldInitLink next; 1169 CtField field; 1170 CtField.Initializer init; 1171 1172 FieldInitLink(CtField f, CtField.Initializer i) { 1173 next = null; 1174 field = f; 1175 init = i; 1176 } 1177} 1178 | Popular Tags |