1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16 package javassist; 17 18 import java.lang.ref.WeakReference; 19 import java.io.BufferedInputStream; 20 import java.io.ByteArrayOutputStream; 21 import java.io.ByteArrayInputStream; 22 import java.io.DataInputStream; 23 import java.io.DataOutputStream; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.net.URL; 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 import java.util.Hashtable; 30 import java.util.List; 31 import java.util.Set; 32 33 import javassist.bytecode.AccessFlag; 34 import javassist.bytecode.AttributeInfo; 35 import javassist.bytecode.AnnotationsAttribute; 36 import javassist.bytecode.BadBytecode; 37 import javassist.bytecode.Bytecode; 38 import javassist.bytecode.ClassFile; 39 import javassist.bytecode.CodeAttribute; 40 import javassist.bytecode.ConstantAttribute; 41 import javassist.bytecode.CodeIterator; 42 import javassist.bytecode.ConstPool; 43 import javassist.bytecode.Descriptor; 44 import javassist.bytecode.EnclosingMethodAttribute; 45 import javassist.bytecode.FieldInfo; 46 import javassist.bytecode.InnerClassesAttribute; 47 import javassist.bytecode.MethodInfo; 48 import javassist.bytecode.ParameterAnnotationsAttribute; 49 import javassist.bytecode.annotation.Annotation; 50 import javassist.compiler.AccessorMaker; 51 import javassist.compiler.CompileError; 52 import javassist.compiler.Javac; 53 import javassist.expr.ExprEditor; 54 55 /** 56 * Class types. 57 */ 58 class CtClassType extends CtClass { 59 ClassPool classPool; 60 boolean wasChanged; 61 private boolean wasFrozen; 62 boolean wasPruned; 63 boolean gcConstPool; // if true, the constant pool entries will be garbage collected. 64 ClassFile classfile; 65 byte[] rawClassfile; // backup storage 66 67 private WeakReference memberCache; 68 private AccessorMaker accessors; 69 70 private FieldInitLink fieldInitializers; 71 private Hashtable hiddenMethods; // must be synchronous 72 private int uniqueNumberSeed; 73 74 private boolean doPruning = ClassPool.doPruning; 75 private int getCount; 76 private static final int GET_THRESHOLD = 2; // see compress() 77 78 CtClassType(String name, ClassPool cp) { 79 super(name); 80 classPool = cp; 81 wasChanged = wasFrozen = wasPruned = gcConstPool = false; 82 classfile = null; 83 rawClassfile = null; 84 memberCache = null; 85 accessors = null; 86 fieldInitializers = null; 87 hiddenMethods = null; 88 uniqueNumberSeed = 0; 89 getCount = 0; 90 } 91 92 CtClassType(InputStream ins, ClassPool cp) throws IOException { 93 this((String)null, cp); 94 classfile = new ClassFile(new DataInputStream(ins)); 95 qualifiedName = classfile.getName(); 96 } 97 98 protected void extendToString(StringBuffer buffer) { 99 if (wasChanged) 100 buffer.append("changed "); 101 102 if (wasFrozen) 103 buffer.append("frozen "); 104 105 if (wasPruned) 106 buffer.append("pruned "); 107 108 buffer.append(Modifier.toString(getModifiers())); 109 buffer.append(" class "); 110 buffer.append(getName()); 111 112 try { 113 CtClass ext = getSuperclass(); 114 if (ext != null) { 115 String name = ext.getName(); 116 if (!name.equals("java.lang.Object")) 117 buffer.append(" extends " + ext.getName()); 118 } 119 } 120 catch (NotFoundException e) { 121 buffer.append(" extends ??"); 122 } 123 124 try { 125 CtClass[] intf = getInterfaces(); 126 if (intf.length > 0) 127 buffer.append(" implements "); 128 129 for (int i = 0; i < intf.length; ++i) { 130 buffer.append(intf[i].getName()); 131 buffer.append(", "); 132 } 133 } 134 catch (NotFoundException e) { 135 buffer.append(" extends ??"); 136 } 137 138 CtMember.Cache memCache = getMembers(); 139 exToString(buffer, " fields=", 140 memCache.fieldHead(), memCache.lastField()); 141 exToString(buffer, " constructors=", 142 memCache.consHead(), memCache.lastCons()); 143 exToString(buffer, " methods=", 144 memCache.methodHead(), memCache.lastMethod()); 145 } 146 147 private void exToString(StringBuffer buffer, String msg, 148 CtMember head, CtMember tail) { 149 buffer.append(msg); 150 while (head != tail) { 151 head = head.next(); 152 buffer.append(head); 153 buffer.append(", "); 154 } 155 } 156 157 public AccessorMaker getAccessorMaker() { 158 if (accessors == null) 159 accessors = new AccessorMaker(this); 160 161 return accessors; 162 } 163 164 public ClassFile getClassFile2() { 165 ClassFile cfile = classfile; 166 if (cfile != null) 167 return cfile; 168 169 classPool.compress(); 170 if (rawClassfile != null) { 171 try { 172 classfile = new ClassFile(new DataInputStream( 173 new ByteArrayInputStream(rawClassfile))); 174 rawClassfile = null; 175 getCount = GET_THRESHOLD; 176 return classfile; 177 } 178 catch (IOException e) { 179 throw new RuntimeException(e.toString(), e); 180 } 181 } 182 183 InputStream fin = null; 184 try { 185 fin = classPool.openClassfile(getName()); 186 if (fin == null) 187 throw new NotFoundException(getName()); 188 189 fin = new BufferedInputStream(fin); 190 ClassFile cf = new ClassFile(new DataInputStream(fin)); 191 if (!cf.getName().equals(qualifiedName)) 192 throw new RuntimeException("cannot find " + qualifiedName + ": " 193 + cf.getName() + " found in " 194 + qualifiedName.replace('.', '/') + ".class"); 195 196 classfile = cf; 197 return cf; 198 } 199 catch (NotFoundException e) { 200 throw new RuntimeException(e.toString(), e); 201 } 202 catch (IOException e) { 203 throw new RuntimeException(e.toString(), e); 204 } 205 finally { 206 if (fin != null) 207 try { 208 fin.close(); 209 } 210 catch (IOException e) {} 211 } 212 } 213 214 /* Inherited from CtClass. Called by get() in ClassPool. 215 * 216 * @see javassist.CtClass#incGetCounter() 217 * @see #toBytecode(DataOutputStream) 218 */ 219 final void incGetCounter() { ++getCount; } 220 221 /** 222 * Invoked from ClassPool#compress(). 223 * It releases the class files that have not been recently used 224 * if they are unmodified. 225 */ 226 void compress() { 227 if (getCount < GET_THRESHOLD) 228 if (!isModified() && ClassPool.releaseUnmodifiedClassFile) 229 removeClassFile(); 230 else if (isFrozen() && !wasPruned) 231 saveClassFile(); 232 233 getCount = 0; 234 } 235 236 /** 237 * Converts a ClassFile object into a byte array 238 * for saving memory space. 239 */ 240 private synchronized void saveClassFile() { 241 /* getMembers() and releaseClassFile() are also synchronized. 242 */ 243 if (classfile == null || hasMemberCache() != null) 244 return; 245 246 ByteArrayOutputStream barray = new ByteArrayOutputStream(); 247 DataOutputStream out = new DataOutputStream(barray); 248 try { 249 classfile.write(out); 250 barray.close(); 251 rawClassfile = barray.toByteArray(); 252 classfile = null; 253 } 254 catch (IOException e) {} 255 } 256 257 private synchronized void removeClassFile() { 258 if (classfile != null && !isModified() && hasMemberCache() == null) 259 classfile = null; 260 } 261 262 public ClassPool getClassPool() { return classPool; } 263 264 void setClassPool(ClassPool cp) { classPool = cp; } 265 266 public URL getURL() throws NotFoundException { 267 URL url = classPool.find(getName()); 268 if (url == null) 269 throw new NotFoundException(getName()); 270 else 271 return url; 272 } 273 274 public boolean isModified() { return wasChanged; } 275 276 public boolean isFrozen() { return wasFrozen; } 277 278 public void freeze() { wasFrozen = true; } 279 280 void checkModify() throws RuntimeException { 281 if (isFrozen()) { 282 String msg = getName() + " class is frozen"; 283 if (wasPruned) 284 msg += " and pruned"; 285 286 throw new RuntimeException(msg); 287 } 288 289 wasChanged = true; 290 } 291 292 public void defrost() { 293 checkPruned("defrost"); 294 wasFrozen = false; 295 } 296 297 public boolean subtypeOf(CtClass clazz) throws NotFoundException { 298 int i; 299 String cname = clazz.getName(); 300 if (this == clazz || getName().equals(cname)) 301 return true; 302 303 ClassFile file = getClassFile2(); 304 String supername = file.getSuperclass(); 305 if (supername != null && supername.equals(cname)) 306 return true; 307 308 String[] ifs = file.getInterfaces(); 309 int num = ifs.length; 310 for (i = 0; i < num; ++i) 311 if (ifs[i].equals(cname)) 312 return true; 313 314 if (supername != null && classPool.get(supername).subtypeOf(clazz)) 315 return true; 316 317 for (i = 0; i < num; ++i) 318 if (classPool.get(ifs[i]).subtypeOf(clazz)) 319 return true; 320 321 return false; 322 } 323 324 public void setName(String name) throws RuntimeException { 325 String oldname = getName(); 326 if (name.equals(oldname)) 327 return; 328 329 // check this in advance although classNameChanged() below does. 330 classPool.checkNotFrozen(name); 331 ClassFile cf = getClassFile2(); 332 super.setName(name); 333 cf.setName(name); 334 nameReplaced(); 335 classPool.classNameChanged(oldname, this); 336 } 337 338 public void replaceClassName(ClassMap classnames) 339 throws RuntimeException 340 { 341 String oldClassName = getName(); 342 String newClassName 343 = (String)classnames.get(Descriptor.toJvmName(oldClassName)); 344 if (newClassName != null) { 345 newClassName = Descriptor.toJavaName(newClassName); 346 // check this in advance although classNameChanged() below does. 347 classPool.checkNotFrozen(newClassName); 348 } 349 350 super.replaceClassName(classnames); 351 ClassFile cf = getClassFile2(); 352 cf.renameClass(classnames); 353 nameReplaced(); 354 355 if (newClassName != null) { 356 super.setName(newClassName); 357 classPool.classNameChanged(oldClassName, this); 358 } 359 } 360 361 public void replaceClassName(String oldname, String newname) 362 throws RuntimeException 363 { 364 String thisname = getName(); 365 if (thisname.equals(oldname)) 366 setName(newname); 367 else { 368 super.replaceClassName(oldname, newname); 369 getClassFile2().renameClass(oldname, newname); 370 nameReplaced(); 371 } 372 } 373 374 public boolean isInterface() { 375 return Modifier.isInterface(getModifiers()); 376 } 377 378 public boolean isAnnotation() { 379 return Modifier.isAnnotation(getModifiers()); 380 } 381 382 public boolean isEnum() { 383 return Modifier.isEnum(getModifiers()); 384 } 385 386 public int getModifiers() { 387 ClassFile cf = getClassFile2(); 388 int acc = cf.getAccessFlags(); 389 acc = AccessFlag.clear(acc, AccessFlag.SUPER); 390 int inner = cf.getInnerAccessFlags(); 391 if (inner != -1 && (inner & AccessFlag.STATIC) != 0) 392 acc |= AccessFlag.STATIC; 393 394 return AccessFlag.toModifier(acc); 395 } 396 397 public CtClass[] getNestedClasses() throws NotFoundException { 398 ClassFile cf = getClassFile2(); 399 InnerClassesAttribute ica 400 = (InnerClassesAttribute)cf.getAttribute(InnerClassesAttribute.tag); 401 if (ica == null) 402 return new CtClass[0]; 403 404 String thisName = cf.getName() + "$"; 405 int n = ica.tableLength(); 406 ArrayList list = new ArrayList(n); 407 for (int i = 0; i < n; i++) { 408 String name = ica.innerClass(i); 409 if (name != null) 410 if (name.startsWith(thisName)) { 411 // if it is an immediate nested class 412 if (name.lastIndexOf('$') < thisName.length()) 413 list.add(classPool.get(name)); 414 } 415 } 416 417 return (CtClass[])list.toArray(new CtClass[list.size()]); 418 } 419 420 public void setModifiers(int mod) { 421 ClassFile cf = getClassFile2(); 422 if (Modifier.isStatic(mod)) { 423 int flags = cf.getInnerAccessFlags(); 424 if (flags != -1 && (flags & AccessFlag.STATIC) != 0) 425 mod = mod & ~Modifier.STATIC; 426 else 427 throw new RuntimeException("cannot change " + getName() + " into a static class"); 428 } 429 430 checkModify(); 431 cf.setAccessFlags(AccessFlag.of(mod)); 432 } 433 434 public boolean hasAnnotation(Class clz) { 435 ClassFile cf = getClassFile2(); 436 AnnotationsAttribute ainfo = (AnnotationsAttribute) 437 cf.getAttribute(AnnotationsAttribute.invisibleTag); 438 AnnotationsAttribute ainfo2 = (AnnotationsAttribute) 439 cf.getAttribute(AnnotationsAttribute.visibleTag); 440 return hasAnnotationType(clz, getClassPool(), ainfo, ainfo2); 441 } 442 443 static boolean hasAnnotationType(Class clz, ClassPool cp, 444 AnnotationsAttribute a1, AnnotationsAttribute a2) 445 { 446 Annotation[] anno1, anno2; 447 448 if (a1 == null) 449 anno1 = null; 450 else 451 anno1 = a1.getAnnotations(); 452 453 if (a2 == null) 454 anno2 = null; 455 else 456 anno2 = a2.getAnnotations(); 457 458 String typeName = clz.getName(); 459 if (anno1 != null) 460 for (int i = 0; i < anno1.length; i++) 461 if (anno1[i].getTypeName().equals(typeName)) 462 return true; 463 464 if (anno2 != null) 465 for (int i = 0; i < anno2.length; i++) 466 if (anno2[i].getTypeName().equals(typeName)) 467 return true; 468 469 return false; 470 } 471 472 public Object getAnnotation(Class clz) throws ClassNotFoundException { 473 ClassFile cf = getClassFile2(); 474 AnnotationsAttribute ainfo = (AnnotationsAttribute) 475 cf.getAttribute(AnnotationsAttribute.invisibleTag); 476 AnnotationsAttribute ainfo2 = (AnnotationsAttribute) 477 cf.getAttribute(AnnotationsAttribute.visibleTag); 478 return getAnnotationType(clz, getClassPool(), ainfo, ainfo2); 479 } 480 481 static Object getAnnotationType(Class clz, ClassPool cp, 482 AnnotationsAttribute a1, AnnotationsAttribute a2) 483 throws ClassNotFoundException 484 { 485 Annotation[] anno1, anno2; 486 487 if (a1 == null) 488 anno1 = null; 489 else 490 anno1 = a1.getAnnotations(); 491 492 if (a2 == null) 493 anno2 = null; 494 else 495 anno2 = a2.getAnnotations(); 496 497 String typeName = clz.getName(); 498 if (anno1 != null) 499 for (int i = 0; i < anno1.length; i++) 500 if (anno1[i].getTypeName().equals(typeName)) 501 return toAnnoType(anno1[i], cp); 502 503 if (anno2 != null) 504 for (int i = 0; i < anno2.length; i++) 505 if (anno2[i].getTypeName().equals(typeName)) 506 return toAnnoType(anno2[i], cp); 507 508 return null; 509 } 510 511 public Object[] getAnnotations() throws ClassNotFoundException { 512 return getAnnotations(false); 513 } 514 515 public Object[] getAvailableAnnotations(){ 516 try { 517 return getAnnotations(true); 518 } 519 catch (ClassNotFoundException e) { 520 throw new RuntimeException("Unexpected exception ", e); 521 } 522 } 523 524 private Object[] getAnnotations(boolean ignoreNotFound) 525 throws ClassNotFoundException 526 { 527 ClassFile cf = getClassFile2(); 528 AnnotationsAttribute ainfo = (AnnotationsAttribute) 529 cf.getAttribute(AnnotationsAttribute.invisibleTag); 530 AnnotationsAttribute ainfo2 = (AnnotationsAttribute) 531 cf.getAttribute(AnnotationsAttribute.visibleTag); 532 return toAnnotationType(ignoreNotFound, getClassPool(), ainfo, ainfo2); 533 } 534 535 static Object[] toAnnotationType(boolean ignoreNotFound, ClassPool cp, 536 AnnotationsAttribute a1, AnnotationsAttribute a2) 537 throws ClassNotFoundException 538 { 539 Annotation[] anno1, anno2; 540 int size1, size2; 541 542 if (a1 == null) { 543 anno1 = null; 544 size1 = 0; 545 } 546 else { 547 anno1 = a1.getAnnotations(); 548 size1 = anno1.length; 549 } 550 551 if (a2 == null) { 552 anno2 = null; 553 size2 = 0; 554 } 555 else { 556 anno2 = a2.getAnnotations(); 557 size2 = anno2.length; 558 } 559 560 if (!ignoreNotFound){ 561 Object[] result = new Object[size1 + size2]; 562 for (int i = 0; i < size1; i++) 563 result[i] = toAnnoType(anno1[i], cp); 564 565 for (int j = 0; j < size2; j++) 566 result[j + size1] = toAnnoType(anno2[j], cp); 567 568 return result; 569 } 570 else{ 571 ArrayList annotations = new ArrayList(); 572 for (int i = 0 ; i < size1 ; i++){ 573 try{ 574 annotations.add(toAnnoType(anno1[i], cp)); 575 } 576 catch(ClassNotFoundException e){} 577 } 578 for (int j = 0; j < size2; j++) { 579 try{ 580 annotations.add(toAnnoType(anno2[j], cp)); 581 } 582 catch(ClassNotFoundException e){} 583 } 584 585 return annotations.toArray(); 586 } 587 } 588 589 static Object[][] toAnnotationType(boolean ignoreNotFound, ClassPool cp, 590 ParameterAnnotationsAttribute a1, 591 ParameterAnnotationsAttribute a2, 592 MethodInfo minfo) 593 throws ClassNotFoundException 594 { 595 int numParameters = 0; 596 if (a1 != null) 597 numParameters = a1.numParameters(); 598 else if (a2 != null) 599 numParameters = a2.numParameters(); 600 else 601 numParameters = Descriptor.numOfParameters(minfo.getDescriptor()); 602 603 Object[][] result = new Object[numParameters][]; 604 for (int i = 0; i < numParameters; i++) { 605 Annotation[] anno1, anno2; 606 int size1, size2; 607 608 if (a1 == null) { 609 anno1 = null; 610 size1 = 0; 611 } 612 else { 613 anno1 = a1.getAnnotations()[i]; 614 size1 = anno1.length; 615 } 616 617 if (a2 == null) { 618 anno2 = null; 619 size2 = 0; 620 } 621 else { 622 anno2 = a2.getAnnotations()[i]; 623 size2 = anno2.length; 624 } 625 626 if (!ignoreNotFound){ 627 result[i] = new Object[size1 + size2]; 628 for (int j = 0; j < size1; ++j) 629 result[i][j] = toAnnoType(anno1[j], cp); 630 631 for (int j = 0; j < size2; ++j) 632 result[i][j + size1] = toAnnoType(anno2[j], cp); 633 } 634 else{ 635 ArrayList annotations = new ArrayList(); 636 for (int j = 0 ; j < size1 ; j++){ 637 try{ 638 annotations.add(toAnnoType(anno1[j], cp)); 639 } 640 catch(ClassNotFoundException e){} 641 } 642 for (int j = 0; j < size2; j++){ 643 try{ 644 annotations.add(toAnnoType(anno2[j], cp)); 645 } 646 catch(ClassNotFoundException e){} 647 } 648 649 result[i] = annotations.toArray(); 650 } 651 } 652 653 return result; 654 } 655 656 private static Object toAnnoType(Annotation anno, ClassPool cp) 657 throws ClassNotFoundException 658 { 659 try { 660 ClassLoader cl = cp.getClassLoader(); 661 return anno.toAnnotationType(cl, cp); 662 } 663 catch (ClassNotFoundException e) { 664 ClassLoader cl2 = cp.getClass().getClassLoader(); 665 return anno.toAnnotationType(cl2, cp); 666 } 667 } 668 669 public boolean subclassOf(CtClass superclass) { 670 if (superclass == null) 671 return false; 672 673 String superName = superclass.getName(); 674 CtClass curr = this; 675 try { 676 while (curr != null) { 677 if (curr.getName().equals(superName)) 678 return true; 679 680 curr = curr.getSuperclass(); 681 } 682 } 683 catch (Exception ignored) {} 684 return false; 685 } 686 687 public CtClass getSuperclass() throws NotFoundException { 688 String supername = getClassFile2().getSuperclass(); 689 if (supername == null) 690 return null; 691 else 692 return classPool.get(supername); 693 } 694 695 public void setSuperclass(CtClass clazz) throws CannotCompileException { 696 checkModify(); 697 if (isInterface()) 698 addInterface(clazz); 699 else 700 getClassFile2().setSuperclass(clazz.getName()); 701 } 702 703 public CtClass[] getInterfaces() throws NotFoundException { 704 String[] ifs = getClassFile2().getInterfaces(); 705 int num = ifs.length; 706 CtClass[] ifc = new CtClass[num]; 707 for (int i = 0; i < num; ++i) 708 ifc[i] = classPool.get(ifs[i]); 709 710 return ifc; 711 } 712 713 public void setInterfaces(CtClass[] list) { 714 checkModify(); 715 String[] ifs; 716 if (list == null) 717 ifs = new String[0]; 718 else { 719 int num = list.length; 720 ifs = new String[num]; 721 for (int i = 0; i < num; ++i) 722 ifs[i] = list[i].getName(); 723 } 724 725 getClassFile2().setInterfaces(ifs); 726 } 727 728 public void addInterface(CtClass anInterface) { 729 checkModify(); 730 if (anInterface != null) 731 getClassFile2().addInterface(anInterface.getName()); 732 } 733 734 public CtClass getDeclaringClass() throws NotFoundException { 735 ClassFile cf = getClassFile2(); 736 InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute( 737 InnerClassesAttribute.tag); 738 if (ica == null) 739 return null; 740 741 String name = getName(); 742 int n = ica.tableLength(); 743 for (int i = 0; i < n; ++i) 744 if (name.equals(ica.innerClass(i))) { 745 String outName = ica.outerClass(i); 746 if (outName != null) 747 return classPool.get(outName); 748 else { 749 // maybe anonymous or local class. 750 EnclosingMethodAttribute ema 751 = (EnclosingMethodAttribute)cf.getAttribute( 752 EnclosingMethodAttribute.tag); 753 if (ema != null) 754 return classPool.get(ema.className()); 755 } 756 } 757 758 return null; 759 } 760 761 public CtMethod getEnclosingMethod() throws NotFoundException { 762 ClassFile cf = getClassFile2(); 763 EnclosingMethodAttribute ema 764 = (EnclosingMethodAttribute)cf.getAttribute( 765 EnclosingMethodAttribute.tag); 766 if (ema != null) { 767 CtClass enc = classPool.get(ema.className()); 768 return enc.getMethod(ema.methodName(), ema.methodDescriptor()); 769 } 770 771 return null; 772 } 773 774 public CtClass makeNestedClass(String name, boolean isStatic) { 775 if (!isStatic) 776 throw new RuntimeException( 777 "sorry, only nested static class is supported"); 778 779 checkModify(); 780 CtClass c = classPool.makeNestedClass(getName() + "$" + name); 781 ClassFile cf = getClassFile2(); 782 ClassFile cf2 = c.getClassFile2(); 783 InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute( 784 InnerClassesAttribute.tag); 785 if (ica == null) { 786 ica = new InnerClassesAttribute(cf.getConstPool()); 787 cf.addAttribute(ica); 788 } 789 790 ica.append(c.getName(), this.getName(), name, 791 (cf2.getAccessFlags() & ~AccessFlag.SUPER) | AccessFlag.STATIC); 792 cf2.addAttribute(ica.copy(cf2.getConstPool(), null)); 793 return c; 794 } 795 796 /* flush cached names. 797 */ 798 private void nameReplaced() { 799 CtMember.Cache cache = hasMemberCache(); 800 if (cache != null) { 801 CtMember mth = cache.methodHead(); 802 CtMember tail = cache.lastMethod(); 803 while (mth != tail) { 804 mth = mth.next(); 805 mth.nameReplaced(); 806 } 807 } 808 } 809 810 /** 811 * Returns null if members are not cached. 812 */ 813 protected CtMember.Cache hasMemberCache() { 814 if (memberCache != null) 815 return (CtMember.Cache)memberCache.get(); 816 else 817 return null; 818 } 819 820 protected synchronized CtMember.Cache getMembers() { 821 CtMember.Cache cache = null; 822 if (memberCache == null 823 || (cache = (CtMember.Cache)memberCache.get()) == null) { 824 cache = new CtMember.Cache(this); 825 makeFieldCache(cache); 826 makeBehaviorCache(cache); 827 memberCache = new WeakReference(cache); 828 } 829 830 return cache; 831 } 832 833 private void makeFieldCache(CtMember.Cache cache) { 834 List list = getClassFile2().getFields(); 835 int n = list.size(); 836 for (int i = 0; i < n; ++i) { 837 FieldInfo finfo = (FieldInfo)list.get(i); 838 CtField newField = new CtField(finfo, this); 839 cache.addField(newField); 840 } 841 } 842 843 private void makeBehaviorCache(CtMember.Cache cache) { 844 List list = getClassFile2().getMethods(); 845 int n = list.size(); 846 for (int i = 0; i < n; ++i) { 847 MethodInfo minfo = (MethodInfo)list.get(i); 848 if (minfo.isMethod()) { 849 CtMethod newMethod = new CtMethod(minfo, this); 850 cache.addMethod(newMethod); 851 } 852 else { 853 CtConstructor newCons = new CtConstructor(minfo, this); 854 cache.addConstructor(newCons); 855 } 856 } 857 } 858 859 public CtField[] getFields() { 860 ArrayList alist = new ArrayList(); 861 getFields(alist, this); 862 return (CtField[])alist.toArray(new CtField[alist.size()]); 863 } 864 865 private static void getFields(ArrayList alist, CtClass cc) { 866 int i, num; 867 if (cc == null) 868 return; 869 870 try { 871 getFields(alist, cc.getSuperclass()); 872 } 873 catch (NotFoundException e) {} 874 875 try { 876 CtClass[] ifs = cc.getInterfaces(); 877 num = ifs.length; 878 for (i = 0; i < num; ++i) 879 getFields(alist, ifs[i]); 880 } 881 catch (NotFoundException e) {} 882 883 CtMember.Cache memCache = ((CtClassType)cc).getMembers(); 884 CtMember field = memCache.fieldHead(); 885 CtMember tail = memCache.lastField(); 886 while (field != tail) { 887 field = field.next(); 888 if (!Modifier.isPrivate(field.getModifiers())) 889 alist.add(field); 890 } 891 } 892 893 public CtField getField(String name, String desc) throws NotFoundException { 894 CtField f = getField2(name, desc); 895 return checkGetField(f, name, desc); 896 } 897 898 private CtField checkGetField(CtField f, String name, String desc) 899 throws NotFoundException 900 { 901 if (f == null) { 902 String msg = "field: " + name; 903 if (desc != null) 904 msg += " type " + desc; 905 906 throw new NotFoundException(msg + " in " + getName()); 907 } 908 else 909 return f; 910 } 911 912 CtField getField2(String name, String desc) { 913 CtField df = getDeclaredField2(name, desc); 914 if (df != null) 915 return df; 916 917 try { 918 CtClass[] ifs = getInterfaces(); 919 int num = ifs.length; 920 for (int i = 0; i < num; ++i) { 921 CtField f = ifs[i].getField2(name, desc); 922 if (f != null) 923 return f; 924 } 925 926 CtClass s = getSuperclass(); 927 if (s != null) 928 return s.getField2(name, desc); 929 } 930 catch (NotFoundException e) {} 931 return null; 932 } 933 934 public CtField[] getDeclaredFields() { 935 CtMember.Cache memCache = getMembers(); 936 CtMember field = memCache.fieldHead(); 937 CtMember tail = memCache.lastField(); 938 int num = CtMember.Cache.count(field, tail); 939 CtField[] cfs = new CtField[num]; 940 int i = 0; 941 while (field != tail) { 942 field = field.next(); 943 cfs[i++] = (CtField)field; 944 } 945 946 return cfs; 947 } 948 949 public CtField getDeclaredField(String name) throws NotFoundException { 950 return getDeclaredField(name, null); 951 } 952 953 public CtField getDeclaredField(String name, String desc) throws NotFoundException { 954 CtField f = getDeclaredField2(name, desc); 955 return checkGetField(f, name, desc); 956 } 957 958 private CtField getDeclaredField2(String name, String desc) { 959 CtMember.Cache memCache = getMembers(); 960 CtMember field = memCache.fieldHead(); 961 CtMember tail = memCache.lastField(); 962 while (field != tail) { 963 field = field.next(); 964 if (field.getName().equals(name) 965 && (desc == null || desc.equals(field.getSignature()))) 966 return (CtField)field; 967 } 968 969 return null; 970 } 971 972 public CtBehavior[] getDeclaredBehaviors() { 973 CtMember.Cache memCache = getMembers(); 974 CtMember cons = memCache.consHead(); 975 CtMember consTail = memCache.lastCons(); 976 int cnum = CtMember.Cache.count(cons, consTail); 977 CtMember mth = memCache.methodHead(); 978 CtMember mthTail = memCache.lastMethod(); 979 int mnum = CtMember.Cache.count(mth, mthTail); 980 981 CtBehavior[] cb = new CtBehavior[cnum + mnum]; 982 int i = 0; 983 while (cons != consTail) { 984 cons = cons.next(); 985 cb[i++] = (CtBehavior)cons; 986 } 987 988 while (mth != mthTail) { 989 mth = mth.next(); 990 cb[i++] = (CtBehavior)mth; 991 } 992 993 return cb; 994 } 995 996 public CtConstructor[] getConstructors() { 997 CtMember.Cache memCache = getMembers(); 998 CtMember cons = memCache.consHead(); 999 CtMember consTail = memCache.lastCons(); 1000 1001 int n = 0; 1002 CtMember mem = cons; 1003 while (mem != consTail) { 1004 mem = mem.next(); 1005 if (isPubCons((CtConstructor)mem)) 1006 n++; 1007 } 1008 1009 CtConstructor[] result = new CtConstructor[n]; 1010 int i = 0; 1011 mem = cons; 1012 while (mem != consTail) { 1013 mem = mem.next(); 1014 CtConstructor cc = (CtConstructor)mem; 1015 if (isPubCons(cc)) 1016 result[i++] = cc; 1017 } 1018 1019 return result; 1020 } 1021 1022 private static boolean isPubCons(CtConstructor cons) { 1023 return !Modifier.isPrivate(cons.getModifiers()) 1024 && cons.isConstructor(); 1025 } 1026 1027 public CtConstructor getConstructor(String desc) 1028 throws NotFoundException 1029 { 1030 CtMember.Cache memCache = getMembers(); 1031 CtMember cons = memCache.consHead(); 1032 CtMember consTail = memCache.lastCons(); 1033 1034 while (cons != consTail) { 1035 cons = cons.next(); 1036 CtConstructor cc = (CtConstructor)cons; 1037 if (cc.getMethodInfo2().getDescriptor().equals(desc) 1038 && cc.isConstructor()) 1039 return cc; 1040 } 1041 1042 return super.getConstructor(desc); 1043 } 1044 1045 public CtConstructor[] getDeclaredConstructors() { 1046 CtMember.Cache memCache = getMembers(); 1047 CtMember cons = memCache.consHead(); 1048 CtMember consTail = memCache.lastCons(); 1049 1050 int n = 0; 1051 CtMember mem = cons; 1052 while (mem != consTail) { 1053 mem = mem.next(); 1054 CtConstructor cc = (CtConstructor)mem; 1055 if (cc.isConstructor()) 1056 n++; 1057 } 1058 1059 CtConstructor[] result = new CtConstructor[n]; 1060 int i = 0; 1061 mem = cons; 1062 while (mem != consTail) { 1063 mem = mem.next(); 1064 CtConstructor cc = (CtConstructor)mem; 1065 if (cc.isConstructor()) 1066 result[i++] = cc; 1067 } 1068 1069 return result; 1070 } 1071 1072 public CtConstructor getClassInitializer() { 1073 CtMember.Cache memCache = getMembers(); 1074 CtMember cons = memCache.consHead(); 1075 CtMember consTail = memCache.lastCons(); 1076 1077 while (cons != consTail) { 1078 cons = cons.next(); 1079 CtConstructor cc = (CtConstructor)cons; 1080 if (cc.isClassInitializer()) 1081 return cc; 1082 } 1083 1084 return null; 1085 } 1086 1087 public CtMethod[] getMethods() { 1088 HashMap h = new HashMap(); 1089 getMethods0(h, this); 1090 return (CtMethod[])h.values().toArray(new CtMethod[h.size()]); 1091 } 1092 1093 private static void getMethods0(HashMap h, CtClass cc) { 1094 try { 1095 CtClass[] ifs = cc.getInterfaces(); 1096 int size = ifs.length; 1097 for (int i = 0; i < size; ++i) 1098 getMethods0(h, ifs[i]); 1099 } 1100 catch (NotFoundException e) {} 1101 1102 try { 1103 CtClass s = cc.getSuperclass(); 1104 if (s != null) 1105 getMethods0(h, s); 1106 } 1107 catch (NotFoundException e) {} 1108 1109 if (cc instanceof CtClassType) { 1110 CtMember.Cache memCache = ((CtClassType)cc).getMembers(); 1111 CtMember mth = memCache.methodHead(); 1112 CtMember mthTail = memCache.lastMethod(); 1113 1114 while (mth != mthTail) { 1115 mth = mth.next(); 1116 if (!Modifier.isPrivate(mth.getModifiers())) 1117 h.put(((CtMethod)mth).getStringRep(), mth); 1118 } 1119 } 1120 } 1121 1122 public CtMethod getMethod(String name, String desc) 1123 throws NotFoundException 1124 { 1125 CtMethod m = getMethod0(this, name, desc); 1126 if (m != null) 1127 return m; 1128 else 1129 throw new NotFoundException(name + "(..) is not found in " 1130 + getName()); 1131 } 1132 1133 private static CtMethod getMethod0(CtClass cc, 1134 String name, String desc) { 1135 if (cc instanceof CtClassType) { 1136 CtMember.Cache memCache = ((CtClassType)cc).getMembers(); 1137 CtMember mth = memCache.methodHead(); 1138 CtMember mthTail = memCache.lastMethod(); 1139 1140 while (mth != mthTail) { 1141 mth = mth.next(); 1142 if (mth.getName().equals(name) 1143 && ((CtMethod)mth).getMethodInfo2().getDescriptor().equals(desc)) 1144 return (CtMethod)mth; 1145 } 1146 } 1147 1148 try { 1149 CtClass s = cc.getSuperclass(); 1150 if (s != null) { 1151 CtMethod m = getMethod0(s, name, desc); 1152 if (m != null) 1153 return m; 1154 } 1155 } 1156 catch (NotFoundException e) {} 1157 1158 try { 1159 CtClass[] ifs = cc.getInterfaces(); 1160 int size = ifs.length; 1161 for (int i = 0; i < size; ++i) { 1162 CtMethod m = getMethod0(ifs[i], name, desc); 1163 if (m != null) 1164 return m; 1165 } 1166 } 1167 catch (NotFoundException e) {} 1168 return null; 1169 } 1170 1171 public CtMethod[] getDeclaredMethods() { 1172 CtMember.Cache memCache = getMembers(); 1173 CtMember mth = memCache.methodHead(); 1174 CtMember mthTail = memCache.lastMethod(); 1175 int num = CtMember.Cache.count(mth, mthTail); 1176 CtMethod[] cms = new CtMethod[num]; 1177 int i = 0; 1178 while (mth != mthTail) { 1179 mth = mth.next(); 1180 cms[i++] = (CtMethod)mth; 1181 } 1182 1183 return cms; 1184 } 1185 1186 public CtMethod getDeclaredMethod(String name) throws NotFoundException { 1187 CtMember.Cache memCache = getMembers(); 1188 CtMember mth = memCache.methodHead(); 1189 CtMember mthTail = memCache.lastMethod(); 1190 while (mth != mthTail) { 1191 mth = mth.next(); 1192 if (mth.getName().equals(name)) 1193 return (CtMethod)mth; 1194 } 1195 1196 throw new NotFoundException(name + "(..) is not found in " 1197 + getName()); 1198 } 1199 1200 public CtMethod getDeclaredMethod(String name, CtClass[] params) 1201 throws NotFoundException 1202 { 1203 String desc = Descriptor.ofParameters(params); 1204 CtMember.Cache memCache = getMembers(); 1205 CtMember mth = memCache.methodHead(); 1206 CtMember mthTail = memCache.lastMethod(); 1207 1208 while (mth != mthTail) { 1209 mth = mth.next(); 1210 if (mth.getName().equals(name) 1211 && ((CtMethod)mth).getMethodInfo2().getDescriptor().startsWith(desc)) 1212 return (CtMethod)mth; 1213 } 1214 1215 throw new NotFoundException(name + "(..) is not found in " 1216 + getName()); 1217 } 1218 1219 public void addField(CtField f, String init) 1220 throws CannotCompileException 1221 { 1222 addField(f, CtField.Initializer.byExpr(init)); 1223 } 1224 1225 public void addField(CtField f, CtField.Initializer init) 1226 throws CannotCompileException 1227 { 1228 checkModify(); 1229 if (f.getDeclaringClass() != this) 1230 throw new CannotCompileException("cannot add"); 1231 1232 if (init == null) 1233 init = f.getInit(); 1234 1235 if (init != null) { 1236 init.check(f.getSignature()); 1237 int mod = f.getModifiers(); 1238 if (Modifier.isStatic(mod) && Modifier.isFinal(mod)) 1239 try { 1240 ConstPool cp = getClassFile2().getConstPool(); 1241 int index = init.getConstantValue(cp, f.getType()); 1242 if (index != 0) { 1243 f.getFieldInfo2().addAttribute(new ConstantAttribute(cp, index)); 1244 init = null; 1245 } 1246 } 1247 catch (NotFoundException e) {} 1248 } 1249 1250 getMembers().addField(f); 1251 getClassFile2().addField(f.getFieldInfo2()); 1252 1253 if (init != null) { 1254 FieldInitLink fil = new FieldInitLink(f, init); 1255 FieldInitLink link = fieldInitializers; 1256 if (link == null) 1257 fieldInitializers = fil; 1258 else { 1259 while (link.next != null) 1260 link = link.next; 1261 1262 link.next = fil; 1263 } 1264 } 1265 } 1266 1267 public void removeField(CtField f) throws NotFoundException { 1268 checkModify(); 1269 FieldInfo fi = f.getFieldInfo2(); 1270 ClassFile cf = getClassFile2(); 1271 if (cf.getFields().remove(fi)) { 1272 getMembers().remove(f); 1273 gcConstPool = true; 1274 } 1275 else 1276 throw new NotFoundException(f.toString()); 1277 } 1278 1279 public CtConstructor makeClassInitializer() 1280 throws CannotCompileException 1281 { 1282 CtConstructor clinit = getClassInitializer(); 1283 if (clinit != null) 1284 return clinit; 1285 1286 checkModify(); 1287 ClassFile cf = getClassFile2(); 1288 Bytecode code = new Bytecode(cf.getConstPool(), 0, 0); 1289 modifyClassConstructor(cf, code, 0, 0); 1290 return getClassInitializer(); 1291 } 1292 1293 public void addConstructor(CtConstructor c) 1294 throws CannotCompileException 1295 { 1296 checkModify(); 1297 if (c.getDeclaringClass() != this) 1298 throw new CannotCompileException("cannot add"); 1299 1300 getMembers().addConstructor(c); 1301 getClassFile2().addMethod(c.getMethodInfo2()); 1302 } 1303 1304 public void removeConstructor(CtConstructor m) throws NotFoundException { 1305 checkModify(); 1306 MethodInfo mi = m.getMethodInfo2(); 1307 ClassFile cf = getClassFile2(); 1308 if (cf.getMethods().remove(mi)) { 1309 getMembers().remove(m); 1310 gcConstPool = true; 1311 } 1312 else 1313 throw new NotFoundException(m.toString()); 1314 } 1315 1316 public void addMethod(CtMethod m) throws CannotCompileException { 1317 checkModify(); 1318 if (m.getDeclaringClass() != this) 1319 throw new CannotCompileException("bad declaring class"); 1320 1321 int mod = m.getModifiers(); 1322 if ((getModifiers() & Modifier.INTERFACE) != 0) { 1323 m.setModifiers(mod | Modifier.PUBLIC); 1324 if ((mod & Modifier.ABSTRACT) == 0) 1325 throw new CannotCompileException( 1326 "an interface method must be abstract: " + m.toString()); 1327 } 1328 1329 getMembers().addMethod(m); 1330 getClassFile2().addMethod(m.getMethodInfo2()); 1331 if ((mod & Modifier.ABSTRACT) != 0) 1332 setModifiers(getModifiers() | Modifier.ABSTRACT); 1333 } 1334 1335 public void removeMethod(CtMethod m) throws NotFoundException { 1336 checkModify(); 1337 MethodInfo mi = m.getMethodInfo2(); 1338 ClassFile cf = getClassFile2(); 1339 if (cf.getMethods().remove(mi)) { 1340 getMembers().remove(m); 1341 gcConstPool = true; 1342 } 1343 else 1344 throw new NotFoundException(m.toString()); 1345 } 1346 1347 public byte[] getAttribute(String name) { 1348 AttributeInfo ai = getClassFile2().getAttribute(name); 1349 if (ai == null) 1350 return null; 1351 else 1352 return ai.get(); 1353 } 1354 1355 public void setAttribute(String name, byte[] data) { 1356 checkModify(); 1357 ClassFile cf = getClassFile2(); 1358 cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data)); 1359 } 1360 1361 public void instrument(CodeConverter converter) 1362 throws CannotCompileException 1363 { 1364 checkModify(); 1365 ClassFile cf = getClassFile2(); 1366 ConstPool cp = cf.getConstPool(); 1367 List list = cf.getMethods(); 1368 int n = list.size(); 1369 for (int i = 0; i < n; ++i) { 1370 MethodInfo minfo = (MethodInfo)list.get(i); 1371 converter.doit(this, minfo, cp); 1372 } 1373 } 1374 1375 public void instrument(ExprEditor editor) 1376 throws CannotCompileException 1377 { 1378 checkModify(); 1379 ClassFile cf = getClassFile2(); 1380 List list = cf.getMethods(); 1381 int n = list.size(); 1382 for (int i = 0; i < n; ++i) { 1383 MethodInfo minfo = (MethodInfo)list.get(i); 1384 editor.doit(this, minfo); 1385 } 1386 } 1387 1388 /** 1389 * @see javassist.CtClass#prune() 1390 * @see javassist.CtClass#stopPruning(boolean) 1391 */ 1392 public void prune() { 1393 if (wasPruned) 1394 return; 1395 1396 wasPruned = wasFrozen = true; 1397 getClassFile2().prune(); 1398 } 1399 1400 public void rebuildClassFile() { gcConstPool = true; } 1401 1402 public void toBytecode(DataOutputStream out) 1403 throws CannotCompileException, IOException 1404 { 1405 try { 1406 if (isModified()) { 1407 checkPruned("toBytecode"); 1408 ClassFile cf = getClassFile2(); 1409 if (gcConstPool) { 1410 cf.compact(); 1411 gcConstPool = false; 1412 } 1413 1414 modifyClassConstructor(cf); 1415 modifyConstructors(cf); 1416 cf.write(out); 1417 out.flush(); 1418 fieldInitializers = null; 1419 if (doPruning) { 1420 // to save memory 1421 cf.prune(); 1422 wasPruned = true; 1423 } 1424 } 1425 else { 1426 classPool.writeClassfile(getName(), out); 1427 // to save memory 1428 // classfile = null; 1429 } 1430 1431 getCount = 0; 1432 wasFrozen = true; 1433 } 1434 catch (NotFoundException e) { 1435 throw new CannotCompileException(e); 1436 } 1437 catch (IOException e) { 1438 throw new CannotCompileException(e); 1439 } 1440 } 1441 1442 /* See also checkModified() 1443 */ 1444 private void checkPruned(String method) { 1445 if (wasPruned) 1446 throw new RuntimeException(method + "(): " + getName() 1447 + " was pruned."); 1448 } 1449 1450 public boolean stopPruning(boolean stop) { 1451 boolean prev = !doPruning; 1452 doPruning = !stop; 1453 return prev; 1454 } 1455 1456 private void modifyClassConstructor(ClassFile cf) 1457 throws CannotCompileException, NotFoundException 1458 { 1459 if (fieldInitializers == null) 1460 return; 1461 1462 Bytecode code = new Bytecode(cf.getConstPool(), 0, 0); 1463 Javac jv = new Javac(code, this); 1464 int stacksize = 0; 1465 boolean doInit = false; 1466 for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) { 1467 CtField f = fi.field; 1468 if (Modifier.isStatic(f.getModifiers())) { 1469 doInit = true; 1470 int s = fi.init.compileIfStatic(f.getType(), f.getName(), 1471 code, jv); 1472 if (stacksize < s) 1473 stacksize = s; 1474 } 1475 } 1476 1477 if (doInit) // need an initializer for static fileds. 1478 modifyClassConstructor(cf, code, stacksize, 0); 1479 } 1480 1481 private void modifyClassConstructor(ClassFile cf, Bytecode code, 1482 int stacksize, int localsize) 1483 throws CannotCompileException 1484 { 1485 MethodInfo m = cf.getStaticInitializer(); 1486 if (m == null) { 1487 code.add(Bytecode.RETURN); 1488 code.setMaxStack(stacksize); 1489 code.setMaxLocals(localsize); 1490 m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V"); 1491 m.setAccessFlags(AccessFlag.STATIC); 1492 m.setCodeAttribute(code.toCodeAttribute()); 1493 cf.addMethod(m); 1494 CtMember.Cache cache = hasMemberCache(); 1495 if (cache != null) 1496 cache.addConstructor(new CtConstructor(m, this)); 1497 } 1498 else { 1499 CodeAttribute codeAttr = m.getCodeAttribute(); 1500 if (codeAttr == null) 1501 throw new CannotCompileException("empty <clinit>"); 1502 1503 try { 1504 CodeIterator it = codeAttr.iterator(); 1505 int pos = it.insertEx(code.get()); 1506 it.insert(code.getExceptionTable(), pos); 1507 int maxstack = codeAttr.getMaxStack(); 1508 if (maxstack < stacksize) 1509 codeAttr.setMaxStack(stacksize); 1510 1511 int maxlocals = codeAttr.getMaxLocals(); 1512 if (maxlocals < localsize) 1513 codeAttr.setMaxLocals(localsize); 1514 } 1515 catch (BadBytecode e) { 1516 throw new CannotCompileException(e); 1517 } 1518 } 1519 1520 try { 1521 m.rebuildStackMapIf6(classPool, cf); 1522 } 1523 catch (BadBytecode e) { 1524 throw new CannotCompileException(e); 1525 } 1526 } 1527 1528 private void modifyConstructors(ClassFile cf) 1529 throws CannotCompileException, NotFoundException 1530 { 1531 if (fieldInitializers == null) 1532 return; 1533 1534 ConstPool cp = cf.getConstPool(); 1535 List list = cf.getMethods(); 1536 int n = list.size(); 1537 for (int i = 0; i < n; ++i) { 1538 MethodInfo minfo = (MethodInfo)list.get(i); 1539 if (minfo.isConstructor()) { 1540 CodeAttribute codeAttr = minfo.getCodeAttribute(); 1541 if (codeAttr != null) 1542 try { 1543 Bytecode init = new Bytecode(cp, 0, 1544 codeAttr.getMaxLocals()); 1545 CtClass[] params 1546 = Descriptor.getParameterTypes( 1547 minfo.getDescriptor(), 1548 classPool); 1549 int stacksize = makeFieldInitializer(init, params); 1550 insertAuxInitializer(codeAttr, init, stacksize); 1551 minfo.rebuildStackMapIf6(classPool, cf); 1552 } 1553 catch (BadBytecode e) { 1554 throw new CannotCompileException(e); 1555 } 1556 } 1557 } 1558 } 1559 1560 private static void insertAuxInitializer(CodeAttribute codeAttr, 1561 Bytecode initializer, 1562 int stacksize) 1563 throws BadBytecode 1564 { 1565 CodeIterator it = codeAttr.iterator(); 1566 int index = it.skipSuperConstructor(); 1567 if (index < 0) { 1568 index = it.skipThisConstructor(); 1569 if (index >= 0) 1570 return; // this() is called. 1571 1572 // Neither this() or super() is called. 1573 } 1574 1575 int pos = it.insertEx(initializer.get()); 1576 it.insert(initializer.getExceptionTable(), pos); 1577 int maxstack = codeAttr.getMaxStack(); 1578 if (maxstack < stacksize) 1579 codeAttr.setMaxStack(stacksize); 1580 } 1581 1582 private int makeFieldInitializer(Bytecode code, CtClass[] parameters) 1583 throws CannotCompileException, NotFoundException 1584 { 1585 int stacksize = 0; 1586 Javac jv = new Javac(code, this); 1587 try { 1588 jv.recordParams(parameters, false); 1589 } 1590 catch (CompileError e) { 1591 throw new CannotCompileException(e); 1592 } 1593 1594 for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) { 1595 CtField f = fi.field; 1596 if (!Modifier.isStatic(f.getModifiers())) { 1597 int s = fi.init.compile(f.getType(), f.getName(), code, 1598 parameters, jv); 1599 if (stacksize < s) 1600 stacksize = s; 1601 } 1602 } 1603 1604 return stacksize; 1605 } 1606 1607 // Methods used by CtNewWrappedMethod 1608 1609 Hashtable getHiddenMethods() { 1610 if (hiddenMethods == null) 1611 hiddenMethods = new Hashtable(); 1612 1613 return hiddenMethods; 1614 } 1615 1616 int getUniqueNumber() { return uniqueNumberSeed++; } 1617 1618 public String makeUniqueName(String prefix) { 1619 HashMap table = new HashMap(); 1620 makeMemberList(table); 1621 Set keys = table.keySet(); 1622 String[] methods = new String[keys.size()]; 1623 keys.toArray(methods); 1624 1625 if (notFindInArray(prefix, methods)) 1626 return prefix; 1627 1628 int i = 100; 1629 String name; 1630 do { 1631 if (i > 999) 1632 throw new RuntimeException("too many unique name"); 1633 1634 name = prefix + i++; 1635 } while (!notFindInArray(name, methods)); 1636 return name; 1637 } 1638 1639 private static boolean notFindInArray(String prefix, String[] values) { 1640 int len = values.length; 1641 for (int i = 0; i < len; i++) 1642 if (values[i].startsWith(prefix)) 1643 return false; 1644 1645 return true; 1646 } 1647 1648 private void makeMemberList(HashMap table) { 1649 int mod = getModifiers(); 1650 if (Modifier.isAbstract(mod) || Modifier.isInterface(mod)) 1651 try { 1652 CtClass[] ifs = getInterfaces(); 1653 int size = ifs.length; 1654 for (int i = 0; i < size; i++) { 1655 CtClass ic =ifs[i]; 1656 if (ic != null && ic instanceof CtClassType) 1657 ((CtClassType)ic).makeMemberList(table); 1658 } 1659 } 1660 catch (NotFoundException e) {} 1661 1662 try { 1663 CtClass s = getSuperclass(); 1664 if (s != null && s instanceof CtClassType) 1665 ((CtClassType)s).makeMemberList(table); 1666 } 1667 catch (NotFoundException e) {} 1668 1669 List list = getClassFile2().getMethods(); 1670 int n = list.size(); 1671 for (int i = 0; i < n; i++) { 1672 MethodInfo minfo = (MethodInfo)list.get(i); 1673 table.put(minfo.getName(), this); 1674 } 1675 1676 list = getClassFile2().getFields(); 1677 n = list.size(); 1678 for (int i = 0; i < n; i++) { 1679 FieldInfo finfo = (FieldInfo)list.get(i); 1680 table.put(finfo.getName(), this); 1681 } 1682 } 1683 } 1684 1685 class FieldInitLink { 1686 FieldInitLink next; 1687 CtField field; 1688 CtField.Initializer init; 1689 1690 FieldInitLink(CtField f, CtField.Initializer i) { 1691 next = null; 1692 field = f; 1693 init = i; 1694 } 1695 } 1696