001 package edu.rice.cs.cunit.classFile; 002 003 import edu.rice.cs.cunit.classFile.attributes.AAttributeInfo; 004 import edu.rice.cs.cunit.classFile.attributes.SourceFileAttributeInfo; 005 import edu.rice.cs.cunit.classFile.constantPool.*; 006 import edu.rice.cs.cunit.classFile.constantPool.visitors.*; 007 import edu.rice.cs.cunit.util.PositionDataInputStream; 008 import edu.rice.cs.cunit.util.PositionInputStream; 009 010 import java.io.*; 011 import java.util.ArrayList; 012 import java.util.Set; 013 014 /** 015 * Represents a Java class file. 016 * 017 * @author Mathias Ricken 018 */ 019 public class ClassFile { 020 /** 021 * Major version. 022 */ 023 private short _majorVersion; 024 025 /** 026 * Minor version. 027 */ 028 private short _minorVersion; 029 030 /** 031 * Constant pool. 032 */ 033 private ConstantPool _constantPool = new ConstantPool(); 034 035 /** 036 * Class access flags. 037 */ 038 private short _classAccessFlags; 039 040 /** 041 * Class information about this class. 042 */ 043 private ClassPoolInfo _thisClass; 044 045 /** 046 * Class information about the superclass. 047 */ 048 private ClassPoolInfo _superClass; 049 050 /** 051 * Class information about implemented interfaces. 052 */ 053 private ArrayList<ClassPoolInfo> _interfaces = new ArrayList<ClassPoolInfo>(); 054 055 /** 056 * Fields in the class. 057 */ 058 private ArrayList<FieldInfo> _fields = new ArrayList<FieldInfo>(); 059 060 /** 061 * Methods in the class. 062 */ 063 private ArrayList<MethodInfo> _methods = new ArrayList<MethodInfo>(); 064 065 /** 066 * Attributes of the class. 067 */ 068 private ArrayList<AAttributeInfo> _attributes = new ArrayList<AAttributeInfo>(); 069 070 // Access flags 071 // TODO: Separate class and method access flags? 072 public static final int ACC_PUBLIC = 0x1; 073 public static final int ACC_PRIVATE = 0x2; 074 public static final int ACC_PROTECTED = 0x4; 075 public static final int ACC_STATIC = 0x8; 076 public static final int ACC_FINAL = 0x10; 077 public static final int ACC_SYNCHRONIZED = 0x20; 078 public static final int ACC_VOLATILE = 0x40; 079 public static final int ACC_BRIDGE = 0x40; // for methods 080 public static final int ACC_TRANSIENT = 0x80; 081 public static final int ACC_VARARGS = 0x80; // for methods 082 public static final int ACC_NATIVE = 0x100; 083 public static final int ACC_INTERFACE = 0x200; 084 public static final int ACC_ABSTRACT = 0x400; 085 public static final int ACC_STRICT = 0x800; 086 public static final int ACC_SYNTHETIC = 0x1000; 087 public static final int ACC_ANNOTATION = 0x2000; 088 public static final int ACC_ENUM = 0x4000; 089 090 /** 091 * Java file magic, 0xCAFEBABE. 092 */ 093 private static final int JAVA_FILE_MAGIC = 0xCAFEBABE; 094 095 public ClassFile(short majorVersion, 096 short minorVersion, 097 short classAccessFlags, 098 String thisClassName, 099 String superClassName) { 100 _majorVersion = majorVersion; 101 _minorVersion = minorVersion; 102 103 _constantPool = new ConstantPool(1); 104 _constantPool.add(EmptyPoolInfo.singleton()); 105 106 // Resolve and check constant pool 107 for(APoolInfo cpi : _constantPool) { 108 cpi.resolve(); 109 } 110 111 _classAccessFlags = classAccessFlags; 112 113 // add a new name 114 AUTFPoolInfo thisClassNameInfo = new ASCIIPoolInfo(thisClassName, _constantPool); 115 int[] l = addConstantPoolItems(new APoolInfo[]{thisClassNameInfo}); 116 thisClassNameInfo = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 117 118 // add a new class 119 _thisClass = new ClassPoolInfo(thisClassNameInfo, _constantPool); 120 l = addConstantPoolItems(new APoolInfo[]{_thisClass}); 121 _thisClass = getConstantPoolItem(l[0]).execute(CheckClassVisitor.singleton(), null); 122 123 if (!thisClassName.equals("java/lang/Object")) { 124 // add a new name 125 AUTFPoolInfo superClassNameInfo = new ASCIIPoolInfo(superClassName, _constantPool); 126 l = addConstantPoolItems(new APoolInfo[]{superClassNameInfo}); 127 superClassNameInfo = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 128 129 // add a new class 130 _superClass = new ClassPoolInfo(superClassNameInfo, _constantPool); 131 l = addConstantPoolItems(new APoolInfo[]{_superClass}); 132 _superClass = getConstantPoolItem(l[0]).execute(CheckClassVisitor.singleton(), null); 133 } 134 135 _interfaces = new ArrayList<ClassPoolInfo>(0); 136 _fields = new ArrayList<FieldInfo>(0); 137 _methods = new ArrayList<MethodInfo>(0); 138 _attributes = new ArrayList<AAttributeInfo>(0); 139 } 140 141 /** 142 * Constructor. 143 * 144 * @param in input stream with class file 145 * 146 * @throws IOException 147 * @throws ClassFormatError 148 */ 149 public ClassFile(InputStream in) throws IOException, ClassFormatError { 150 PositionDataInputStream di = new PositionDataInputStream(new PositionInputStream(in)); 151 152 readHeader(di); 153 readConstantPool(di); 154 155 readClassInfo(di); 156 157 readInterfaces(di); 158 readFields(di); 159 readMethods(di); 160 readAttributes(di); 161 } 162 163 /** 164 * Constructor. 165 * 166 * @param b byte array 167 * 168 * @throws IOException 169 * @throws ClassFormatError 170 */ 171 public ClassFile(byte[] b) throws IOException, ClassFormatError { 172 this(new ByteArrayInputStream(b)); 173 } 174 175 /** 176 * Read a class file header 177 * 178 * @param di stream 179 * 180 * @throws IOException 181 * @throws ClassFormatError 182 */ 183 protected void readHeader(PositionDataInputStream di) throws IOException, ClassFormatError { 184 int magic = di.readInt(); 185 if (JAVA_FILE_MAGIC != magic) { 186 throw new ClassFormatError("Wrong _magic"); 187 } 188 189 _minorVersion = di.readShort(); 190 _majorVersion = di.readShort(); 191 } 192 193 /** 194 * Read constant pool. 195 * 196 * @param di stream 197 * 198 * @throws IOException 199 * @throws ClassFormatError 200 */ 201 protected void readConstantPool(PositionDataInputStream di) throws IOException, ClassFormatError { 202 int count = di.readShort(); 203 204 _constantPool = new ConstantPool(count); 205 for(int i = 0; i < count; ++i) { 206 _constantPool.add(EmptyPoolInfo.singleton()); 207 } 208 209 int index = 1; 210 while(index < _constantPool.size()) { 211 APoolInfo cpi = APoolInfo.read(di, _constantPool); 212 _constantPool.set(index, cpi); 213 index += cpi.execute(GetPoolInfoSizeVisitor.singleton(), null); 214 } 215 216 // Resolve and check constant pool 217 for(APoolInfo cpi : _constantPool) { 218 cpi.resolve(); 219 } 220 } 221 222 /** 223 * Read class information. 224 * 225 * @param di stream 226 * 227 * @throws IOException 228 * @throws ClassFormatError 229 */ 230 protected void readClassInfo(PositionDataInputStream di) throws IOException, ClassFormatError { 231 _classAccessFlags = di.readShort(); 232 233 _thisClass = _constantPool.get(di.readShort()).execute(CheckClassVisitor.singleton(), null); 234 short superClassIndex = di.readShort(); 235 if ("java/lang/Object".equals(_thisClass.getName().toString())) { 236 if (0 != superClassIndex) { 237 throw new ClassFormatError("java.lang.Object must have 0 as superclass index"); 238 } 239 } 240 else { 241 _superClass = _constantPool.get(superClassIndex).execute(CheckClassVisitor.singleton(), null); 242 } 243 } 244 245 /** 246 * Read class file interfaces. 247 * 248 * @param di stream 249 * 250 * @throws IOException 251 * @throws ClassFormatError 252 */ 253 protected void readInterfaces(PositionDataInputStream di) throws IOException, ClassFormatError { 254 int count = di.readShort(); 255 if (0 != count) { 256 _interfaces = new ArrayList<ClassPoolInfo>(count); 257 for(int i = 0; i < count; ++i) { 258 _interfaces.add(null); 259 } 260 261 for(int i = 0; i < count; ++i) { 262 int iindex = di.readShort(); 263 if ((1 > iindex) || (iindex > _constantPool.size() - 1)) { 264 throw new ClassFormatError("Interface number out of range, index=" + i); 265 } 266 _interfaces.set(i, _constantPool.get(iindex).execute(CheckClassVisitor.singleton(), null)); 267 } 268 } 269 } 270 271 /** 272 * Read class file fields. 273 * 274 * @param di stream 275 * 276 * @throws IOException 277 * @throws ClassFormatError 278 */ 279 protected void readFields(PositionDataInputStream di) throws IOException, ClassFormatError { 280 int count = di.readShort(); 281 if (0 != count) { 282 _fields = new ArrayList<FieldInfo>(count); 283 for(int i = 0; i < count; ++i) { 284 _fields.add(null); 285 } 286 for(int i = 0; i < count; ++i) { 287 _fields.set(i, new FieldInfo(di, _constantPool)); 288 } 289 } 290 } 291 292 /** 293 * Read class file methods. 294 * 295 * @param di stream 296 * 297 * @throws IOException 298 * @throws ClassFormatError 299 */ 300 protected void readMethods(PositionDataInputStream di) throws IOException, ClassFormatError { 301 int count = di.readShort(); 302 if (0 != count) { 303 _methods = new ArrayList<MethodInfo>(count); 304 for(int i = 0; i < count; ++i) { 305 _methods.add(null); 306 } 307 for(int i = 0; i < count; ++i) { 308 _methods.set(i, new MethodInfo(di, _constantPool)); 309 } 310 } 311 } 312 313 /** 314 * Read class file attributes. 315 * 316 * @param di stream 317 * 318 * @throws IOException 319 * @throws ClassFormatError 320 */ 321 protected void readAttributes(PositionDataInputStream di) throws IOException, ClassFormatError { 322 int count = di.readShort(); 323 if (0 != count) { 324 _attributes = new ArrayList<AAttributeInfo>(count); 325 for(int i = 0; i < count; ++i) { 326 _attributes.add(null); 327 } 328 for(int i = 0; i < count; ++i) { 329 _attributes.set(i, AAttributeInfo.read(di, _constantPool)); 330 } 331 } 332 } 333 334 /** 335 * Write class file into stream. 336 * 337 * @param out stream 338 * 339 * @throws IOException 340 */ 341 public void write(OutputStream out) throws IOException { 342 DataOutputStream dos = new DataOutputStream(out); 343 344 dos.writeInt(JAVA_FILE_MAGIC); 345 dos.writeShort(_minorVersion); 346 dos.writeShort(_majorVersion); 347 348 dos.writeShort(_constantPool.size()); 349 for(APoolInfo cpi : _constantPool) { 350 if (null != cpi) { 351 cpi.write(dos); 352 } 353 } 354 355 dos.writeShort(_classAccessFlags); 356 dos.writeShort(_constantPool.indexOf(_thisClass)); 357 if ("java/lang/Object".equals(_thisClass.getName().toString())) { 358 dos.writeShort(0); 359 } 360 else { 361 dos.writeShort(_constantPool.indexOf(_superClass)); 362 } 363 364 dos.writeShort(_interfaces.size()); 365 for(ClassPoolInfo intrf : _interfaces) { 366 dos.writeShort(_constantPool.indexOf(intrf)); 367 } 368 369 dos.writeShort(_fields.size()); 370 for(FieldInfo field : _fields) { 371 field.write(dos, _constantPool); 372 } 373 374 dos.writeShort(_methods.size()); 375 for(MethodInfo method : _methods) { 376 method.write(dos, _constantPool); 377 } 378 379 dos.writeShort(_attributes.size()); 380 for(AAttributeInfo attr : _attributes) { 381 attr.write(dos); 382 } 383 } 384 385 /** 386 * Return the name of this class. 387 * 388 * @return name of this class 389 */ 390 public String getThisClassName() { 391 return ClassFileTools.getClassName(_thisClass.getName().toString()); 392 } 393 394 /** 395 * Return the name of the super class or the empty string, if this class is java.lang.Object. 396 * 397 * @return name of super class 398 */ 399 public String getSuperClassName() { 400 if (null != _superClass) { 401 return ClassFileTools.getClassName(_superClass.getName().toString()); 402 } 403 else { 404 return ""; 405 } 406 } 407 408 /** 409 * Return a human-readable version of this class. 410 * 411 * @return string 412 */ 413 public String toString() { 414 return "Class File (Version " + _majorVersion + '.' + _minorVersion + ") for class " + _thisClass.getName(); 415 } 416 417 418 /** 419 * Return a verbose human-readable version of this class. 420 * 421 * @return verbose string 422 */ 423 public String toStringVerbose() { 424 return toStringVerbose(true, true); 425 } 426 427 /** 428 * Return a verbose human-readable version of this class. 429 * 430 * @param lineNumbers print line numbers 431 * @param PCs print PC values 432 * @return verbose string 433 */ 434 public String toStringVerbose(boolean lineNumbers, boolean PCs) { 435 StringWriter sw = new StringWriter(); 436 final PrintWriter pw = new PrintWriter(sw); 437 438 // class declaration 439 String thisClassName = getThisClassName(); 440 String superClassName = getSuperClassName(); 441 String packageName = null; 442 443 if (0 < thisClassName.indexOf('.')) { 444 packageName = thisClassName.substring(0, thisClassName.lastIndexOf('.')); 445 thisClassName = thisClassName.substring(thisClassName.lastIndexOf('.') + 1); 446 pw.println("\npackage " + packageName); 447 } 448 449 pw.println(); 450 pw.print("Class file version: "); 451 pw.print(_majorVersion); 452 pw.print("."); 453 pw.println(_minorVersion); 454 pw.println(); 455 456 pw.print( 457 ClassFileTools.getAccessString(_classAccessFlags) + "class " + thisClassName + (!"".equals(superClassName) ? (" extends " + superClassName) : "")); 458 if (0 != _interfaces.size()) { 459 pw.print(" implements "); 460 boolean first = true; 461 for(ClassPoolInfo intrf : _interfaces) { 462 if (first) { first = false; } else { pw.print(", "); } 463 pw.print(ClassFileTools.getClassName(intrf.getName().toString())); 464 } 465 } 466 467 // print constant pool 468 pw.println("\n\nConstant Pool: " + _constantPool.size() + " items"); 469 int i = 0; 470 for(APoolInfo cpi : _constantPool) { 471 pw.println('#' + String.format("%5d", new Object[]{i++}) + ": " + cpi.toStringVerbose()); 472 } 473 474 final Set<String> classesUsed = ClassFileTools.getClassNamesUsed(this); 475 pw.print("\nUsed Classes: " + classesUsed.size() + '\n'); 476 for(String s: classesUsed) { 477 pw.println(s); 478 } 479 480 pw.println("\nAttributes: " + _attributes.size()); 481 i = 0; 482 for(final AAttributeInfo attr : _attributes) { 483 pw.println(" Attribute " + (i++ + 1) + ": " + attr); 484 } 485 486 pw.println("\nFields: " + _fields.size()); 487 for(FieldInfo field : _fields) { 488 pw.println(" " + field.toString(_constantPool)); 489 } 490 491 pw.println("\nMethods: " + _methods.size()); 492 for(MethodInfo method : _methods) { 493 pw.println(" " + method.toString(_constantPool, lineNumbers, PCs)); 494 } 495 496 pw.println(); 497 498 return sw.toString(); 499 } 500 501 /** 502 * Return a constant pool item from this class. This reindexes the constant pool item to make sure the indices are 503 * still correct. 504 * 505 * @param index index of the item 506 * 507 * @return pool item, or null if out of range 508 */ 509 public APoolInfo getConstantPoolItem(int index) { 510 APoolInfo cp; 511 512 assert(index <= 0xFFFF); 513 514 if ((0 >= index) || (index > (_constantPool.size() - 1))) { 515 return null; 516 } 517 cp = _constantPool.get(index); 518 cp.reindex(); 519 return cp; 520 } 521 522 /** 523 * Add new items to the constant pool. The items must have been resolved already. The list is pruned to avoid adding 524 * items to the pool that are already there. 525 * <p/> 526 * The function first goes through the list and identifies all those value items (int, long, float, double, ASCII, 527 * and Unicode) that are already in the pool. If an item is already in the pool, it is not added again. Furthermore, 528 * if an item is an ASCII or Unicode UTF item, then all the references to that item present in the list of new items 529 * are changed to point to the item in pool. This is only done for ASCII and Unicode UTF items since they are the 530 * only ones referenced from other items. 531 * <p/> 532 * This process is repeated for all reference items (class, field, method, interface method, name-and-type, and 533 * string) in the list. Here, only name-and-type and class are referenced from other items, so references to them 534 * are changed to point to the pool if they are already in the pool. 535 * <p/> 536 * Finally, items not yet in the pool are added. 537 * 538 * @param items array of new items 539 * 540 * @return array with indices of added items 541 */ 542 public int[] addConstantPoolItems(final APoolInfo[] items) { 543 final int[] indices = new int[items.length]; 544 545 // process value items 546 for(int jv = 0; jv < items.length; ++jv) { 547 final int j = jv; 548 items[j].execute(new AValueReferencePoolInfoVisitor<Object, Object>() { 549 public Object refCase(APoolInfo host, Object o) { 550 // do nothing, not interested in reference objects right now 551 return null; 552 } 553 554 public Object emptyCase(EmptyPoolInfo host, Object o) { 555 // do nothing 556 return null; 557 } 558 559 public Object valueCase(APoolInfo host, Object o) { 560 // check if this object is already in the pool 561 indices[j] = 0; 562 final APoolInfo newArg = host.inPool(_constantPool); 563 if (null != newArg) { 564 // yes, mark for deletion 565 indices[j] = _constantPool.indexOf(newArg); 566 } 567 568 return null; 569 } 570 571 public Object asciizCase(ASCIIPoolInfo host, Object o) { 572 return utfCase(host, o); 573 } 574 575 public Object unicodeCase(UnicodePoolInfo host, Object o) { 576 return utfCase(host, o); 577 } 578 579 private Object utfCase(AUTFPoolInfo utfHost, Object o) { 580 // check if this object is already in the pool 581 indices[j] = 0; 582 final AUTFPoolInfo newArg = (AUTFPoolInfo)utfHost.inPool(_constantPool); 583 if (null != newArg) { 584 // yes, mark for deletion 585 indices[j] = _constantPool.indexOf(newArg); 586 587 // update references 588 for(APoolInfo cpi : items) { 589 cpi.execute(new AValueReferencePoolInfoVisitor<Object, Object>() { 590 public Object refCase(APoolInfo host, Object o) { 591 // do nothing, these objects don't have UTF references 592 return null; 593 } 594 595 public Object emptyCase(EmptyPoolInfo host, Object o) { 596 // do nothing 597 return null; 598 } 599 600 public Object valueCase(APoolInfo host, Object o) { 601 // do nothing, value objects don't have references 602 return null; 603 } 604 605 public Object classCase(ClassPoolInfo host, Object o) { 606 // class objects have a UTF reference 607 if (host.getName() == newArg) { 608 // this is affected, update it 609 host.setName(newArg); 610 } 611 return null; 612 } 613 614 public Object stringCase(StringPoolInfo host, Object o) { 615 // string objects have a UTF reference 616 if (host.getUtf() == newArg) { 617 // this is affected, update it 618 host.setUtf(newArg); 619 } 620 return null; 621 } 622 623 public Object nameAndTypeCase(NameAndTypePoolInfo host, Object o) { 624 // name and type objects have two UTF references 625 if (host.getName() == newArg) { 626 // this is affected, update it 627 host.setName(newArg); 628 } 629 if (host.getDescriptor() == newArg) { 630 // this is affected, update it 631 host.setDescriptor(newArg); 632 } 633 return null; 634 } 635 }, null); 636 } 637 } 638 639 return null; 640 } 641 }, null); 642 } 643 644 // process reference items 645 for(int jv = 0; jv < items.length; ++jv) { 646 final int j = jv; 647 items[j].execute(new AValueReferencePoolInfoVisitor<Object, Object>() { 648 public Object valueCase(APoolInfo host, Object o) { 649 // do nothing, not interested in reference objects right now 650 return null; 651 } 652 653 public Object emptyCase(EmptyPoolInfo host, Object o) { 654 // do nothing 655 return null; 656 } 657 658 public Object refCase(APoolInfo host, Object o) { 659 // check if this object is already in the pool 660 indices[j] = 0; 661 final APoolInfo newArg = host.inPool(_constantPool); 662 if (null != newArg) { 663 // yes, mark for deletion 664 indices[j] = _constantPool.indexOf(newArg); 665 } 666 667 return null; 668 } 669 670 public Object classCase(ClassPoolInfo host, Object o) { 671 return referencedCase(host, o); 672 } 673 674 public Object nameAndTypeInfo(NameAndTypePoolInfo host, Object o) { 675 return referencedCase(host, o); 676 } 677 678 private Object referencedCase(APoolInfo referencedHost, Object o) { 679 // check if this object is already in the pool 680 indices[j] = 0; 681 final APoolInfo newArg = referencedHost.inPool(_constantPool); 682 if (null != newArg) { 683 // yes, mark for deletion 684 indices[j] = _constantPool.indexOf(newArg); 685 686 // update references 687 for(APoolInfo cpi : items) { 688 cpi.execute(new AValueReferencePoolInfoVisitor<Object, Object>() { 689 public Object valueCase(APoolInfo host, Object o) { 690 // do nothing, value objects don't have references 691 return null; 692 } 693 694 public Object emptyCase(EmptyPoolInfo host, Object o) { 695 // do nothing 696 return null; 697 } 698 699 public Object refCase(APoolInfo host, Object o) { 700 // do nothing, these objects don't have Class or NameAndType references 701 return null; 702 } 703 704 public Object fieldCase(FieldPoolInfo host, Object o) { 705 // field objects have Class and NameAndType references 706 return classNameTypeCase(host, o); 707 } 708 709 public Object methodCase(MethodPoolInfo host, Object o) { 710 // method objects have Class and NameAndType references 711 return classNameTypeCase(host, o); 712 } 713 714 public Object interfaceMethodCase(InterfaceMethodPoolInfo host, Object o) { 715 // interface method objects have Class and NameAndType references 716 return classNameTypeCase(host, o); 717 } 718 719 public Object classNameTypeCase(AClassNameTypePoolInfo host, Object o) { 720 // ClassNameType objects have a Class and a NameAndType references 721 if (host.getClassInfo() == newArg) { 722 // this is affected, update it 723 host.setClassInfo((ClassPoolInfo)newArg); 724 } 725 if (host.getNameAndType() == newArg) { 726 // this is affected, update it 727 host.setNameAndType((NameAndTypePoolInfo)newArg); 728 } 729 return null; 730 } 731 }, null); 732 } 733 } 734 735 return null; 736 } 737 }, null); 738 } 739 740 // add new items to the pool 741 for(int i = 0; i < items.length; ++i) { 742 if (0 == indices[i]) { 743 _constantPool.add(items[i]); 744 // add empty item for long and double 745 items[i].execute(new NoOpPoolInfoVisitor<Object, Object>() { 746 public Object longCase(LongPoolInfo host, Object o) { 747 _constantPool.add(EmptyPoolInfo.singleton()); 748 return null; 749 } 750 751 public Object doubleCase(DoublePoolInfo host, Object o) { 752 _constantPool.add(EmptyPoolInfo.singleton()); 753 return null; 754 } 755 }, null); 756 indices[i] = _constantPool.indexOf(items[i]); 757 assert(indices[i] <= 0xFFFF); 758 } 759 } 760 761 return indices; 762 } 763 764 /** 765 * Add an attribute to the class. 766 * 767 * @param newAttribute new attribute 768 */ 769 public void addAttribute(AAttributeInfo newAttribute) { 770 _attributes.add(newAttribute); 771 } 772 773 /** 774 * Return the attribute with the specified name. 775 * 776 * @param name attribute name 777 * 778 * @return attribute or null if not found 779 */ 780 public AAttributeInfo getAttribute(String name) { 781 if (0 == _attributes.size()) { 782 return null; 783 } 784 for(AAttributeInfo attr : _attributes) { 785 if (0 == name.compareTo(attr.getName().toString())) { 786 return attr; 787 } 788 } 789 return null; 790 } 791 792 /** 793 * Accessor for the minor version. 794 * 795 * @return minor version 796 */ 797 public short getMinorVersion() { 798 return _minorVersion; 799 } 800 801 /** 802 * Mutator for the minor version 803 * 804 * @param minorVersion new minor version 805 */ 806 public void setMinorVersion(short minorVersion) { 807 _minorVersion = minorVersion; 808 } 809 810 /** 811 * Accessor for the major version. 812 * 813 * @return major version 814 */ 815 public short getMajorVersion() { 816 return _majorVersion; 817 } 818 819 /** 820 * Mutator for the major version 821 * 822 * @param majorVersion new major version 823 */ 824 public void setMajorVersion(short majorVersion) { 825 _majorVersion = majorVersion; 826 } 827 828 /** 829 * Accessor for the class access flags. 830 * 831 * @return access flags 832 */ 833 public short getClassAccessFlags() { 834 return _classAccessFlags; 835 } 836 837 /** 838 * Mutator for the class access flags. 839 * 840 * @param classAccessFlags new flags 841 */ 842 public void setClassAccessFlags(short classAccessFlags) { 843 _classAccessFlags = classAccessFlags; 844 } 845 846 /** 847 * Accessor for the superclass. 848 * 849 * @return superclass information 850 */ 851 public ClassPoolInfo getSuperClass() { 852 return _superClass; 853 } 854 855 /** 856 * Mutator for the superclass. 857 * @param cpi superclass information 858 */ 859 public void setSuperClass(ClassPoolInfo cpi) { 860 _superClass = cpi; 861 } 862 863 /** 864 * Accessor for this class. 865 * 866 * @return this class 867 */ 868 public ClassPoolInfo getThisClass() { 869 return _thisClass; 870 } 871 /** 872 * Mutator for the this class. 873 * @param cpi this class information 874 */ 875 public void setThisClass(ClassPoolInfo cpi) { 876 _thisClass = cpi; 877 } 878 879 880 /** 881 * Accessor for the interface list. 882 * 883 * @return interface list 884 */ 885 public ArrayList<ClassPoolInfo> getInterfaces() { 886 return _interfaces; 887 } 888 889 /** 890 * Accessor for the fields list. 891 * 892 * @return fields list 893 */ 894 public ArrayList<FieldInfo> getFields() { 895 return _fields; 896 } 897 898 /** 899 * Accessor for the methods list. 900 * 901 * @return methods list 902 */ 903 public ArrayList<MethodInfo> getMethods() { 904 return _methods; 905 } 906 907 /** 908 * Accessor for the attributes list. 909 * 910 * @return methods list 911 */ 912 public ArrayList<AAttributeInfo> getAttributes() { 913 return _attributes; 914 } 915 916 /** 917 * Accessor for the constant pool. 918 * 919 * @return methods list 920 */ 921 public ConstantPool getConstantPool() { 922 return _constantPool; 923 } 924 925 /** 926 * Add the constant pool items for a method "methodName:methodDescriptor" in class "className". 927 * 928 * @param className class name 929 * @param methodName method name 930 * @param methodDescriptor method descriptor 931 * 932 * @return constant pool index of method info 933 */ 934 public int addMethodToConstantPool(String className, String methodName, String methodDescriptor) { 935 ConstantPool cp = getConstantPool(); 936 937 int[] l; 938 939 // add a new name for the monitor class 940 AUTFPoolInfo monitorClassName = new ASCIIPoolInfo(className, cp); 941 l = addConstantPoolItems(new APoolInfo[]{monitorClassName}); 942 // Debug.out.println("monitorClassName index = " + l[0]); 943 monitorClassName = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 944 945 // add a new class for the monitor class 946 ClassPoolInfo monitorClass = new ClassPoolInfo(monitorClassName, cp); 947 l = addConstantPoolItems(new APoolInfo[]{monitorClass}); 948 // Debug.out.println("monitorClass index = " + l[0]); 949 monitorClass = getConstantPoolItem(l[0]).execute(CheckClassVisitor.singleton(), null); 950 951 // add a new method name for the method 952 AUTFPoolInfo methodNameInfo = new ASCIIPoolInfo(methodName, cp); 953 l = addConstantPoolItems(new APoolInfo[]{methodNameInfo}); 954 // Debug.out.println("methodNameInfo index = " + l[0]); 955 methodNameInfo = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 956 957 // add a new type name for the method 958 AUTFPoolInfo methodTypeName = new ASCIIPoolInfo(methodDescriptor, cp); 959 l = addConstantPoolItems(new APoolInfo[]{methodTypeName}); 960 // Debug.out.println("methodTypeName index = " + l[0]); 961 methodTypeName = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 962 963 // add a new name-and-type for the method 964 NameAndTypePoolInfo methodNaT = new NameAndTypePoolInfo(methodNameInfo, methodTypeName, cp); 965 l = addConstantPoolItems(new APoolInfo[]{methodNaT}); 966 // Debug.out.println("methodNaT index = " + l[0]); 967 methodNaT = getConstantPoolItem(l[0]).execute(CheckNameAndTypeVisitor.singleton(), null); 968 969 // add a new method info for the method 970 MethodPoolInfo method = new MethodPoolInfo(monitorClass, methodNaT, cp); 971 l = addConstantPoolItems(new APoolInfo[]{method}); 972 // Debug.out.println("method index = " + l[0]); 973 method = getConstantPoolItem(l[0]).execute(CheckMethodVisitor.singleton(), null); 974 975 return l[0]; 976 } 977 978 /** 979 * Add a long constant value to the constant pool. 980 * @param value constant value 981 * @return constant pool index 982 */ 983 public int addLongToConstantPool(long value) { 984 int[] l; 985 LongPoolInfo syncBlockCodeLong = new LongPoolInfo(value, _constantPool); 986 l = addConstantPoolItems(new APoolInfo[]{syncBlockCodeLong}); 987 syncBlockCodeLong = getConstantPoolItem(l[0]).execute(CheckLongVisitor.singleton(), null); 988 return l[0]; 989 } 990 991 /** 992 * Add the constant pool items for a field "fieldName:fieldDescriptor" in class "className". 993 * 994 * @param className class name 995 * @param fieldName field name 996 * @param fieldDescriptor field descriptor 997 * @param addToFields true if a new field should be added to the fields list as well 998 * @param accessFlags access flags (only if addToFields is true) 999 * 1000 * @return constant pool index of field info 1001 */ 1002 public int addField(String className, String fieldName, String fieldDescriptor, boolean addToFields, 1003 short accessFlags) { 1004 ConstantPool cp = getConstantPool(); 1005 1006 int[] l; 1007 1008 // add a new name 1009 AUTFPoolInfo fieldClassName = new ASCIIPoolInfo(className, cp); 1010 l = addConstantPoolItems(new APoolInfo[]{fieldClassName}); 1011 fieldClassName = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 1012 1013 // add a new class 1014 ClassPoolInfo fieldClass = new ClassPoolInfo(fieldClassName, cp); 1015 l = addConstantPoolItems(new APoolInfo[]{fieldClass}); 1016 fieldClass = getConstantPoolItem(l[0]).execute(CheckClassVisitor.singleton(), null); 1017 1018 // add a new field name for the field 1019 AUTFPoolInfo fieldNameInfo = new ASCIIPoolInfo(fieldName, cp); 1020 l = addConstantPoolItems(new APoolInfo[]{fieldNameInfo}); 1021 fieldNameInfo = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 1022 1023 // add a new type name for the field 1024 AUTFPoolInfo fieldTypeName = new ASCIIPoolInfo(fieldDescriptor, cp); 1025 l = addConstantPoolItems(new APoolInfo[]{fieldTypeName}); 1026 fieldTypeName = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 1027 1028 // add a new name-and-type for the field 1029 NameAndTypePoolInfo fieldNaT = new NameAndTypePoolInfo(fieldNameInfo, fieldTypeName, cp); 1030 l = addConstantPoolItems(new APoolInfo[]{fieldNaT}); 1031 fieldNaT = getConstantPoolItem(l[0]).execute(CheckNameAndTypeVisitor.singleton(), null); 1032 1033 // add a new field info for the field 1034 FieldPoolInfo field = new FieldPoolInfo(fieldClass, fieldNaT, cp); 1035 l = addConstantPoolItems(new APoolInfo[]{field}); 1036 field = getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<FieldPoolInfo, Object>() { 1037 public FieldPoolInfo defaultCase(APoolInfo host, Object param) { 1038 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be FieldPoolInfo"); 1039 } 1040 1041 public FieldPoolInfo fieldCase(FieldPoolInfo host, Object param) { 1042 return host; 1043 } 1044 }, null); 1045 1046 if (addToFields) { 1047 FieldInfo fi = new FieldInfo(accessFlags, fieldNameInfo, fieldTypeName, new SourceFileAttributeInfo[] {}); 1048 getFields().add(fi); 1049 } 1050 1051 return l[0]; 1052 } 1053 1054 /** 1055 * Find the method info in the constant pool for a method "methodName:methodDescriptor" in class "className". 1056 * 1057 * @param className class name 1058 * @param methodName method name 1059 * @param methodDescriptor method descriptor 1060 * 1061 * @return constant pool index of the method, or 0 if not found 1062 */ 1063 public int findMethodInConstantPool(String className, String methodName, String methodDescriptor) { 1064 ConstantPool cp = getConstantPool(); 1065 1066 int[] l; 1067 APoolInfo newArg; 1068 1069 // add a new name for the monitor class 1070 AUTFPoolInfo monitorClassName = new ASCIIPoolInfo(className, cp); 1071 newArg = (AUTFPoolInfo)monitorClassName.inPool(cp); 1072 if (null == newArg) { 1073 // not found 1074 return 0; 1075 } 1076 monitorClassName = newArg.execute(CheckUTFVisitor.singleton(), null); 1077 1078 // add a new class for the monitor class 1079 ClassPoolInfo monitorClass = new ClassPoolInfo(monitorClassName, cp); 1080 newArg = monitorClass.inPool(cp); 1081 if (null == newArg) { 1082 // not found 1083 return 0; 1084 } 1085 monitorClass = newArg.execute(CheckClassVisitor.singleton(), null); 1086 1087 // add a new method name for the method 1088 AUTFPoolInfo methodNameInfo = new ASCIIPoolInfo(methodName, cp); 1089 newArg = methodNameInfo.inPool(cp); 1090 if (null == newArg) { 1091 // not found 1092 return 0; 1093 } 1094 methodNameInfo = newArg.execute(CheckUTFVisitor.singleton(), null); 1095 1096 // add a new type name for the method 1097 AUTFPoolInfo methodTypeName = new ASCIIPoolInfo(methodDescriptor, cp); 1098 newArg = methodTypeName.inPool(cp); 1099 if (null == newArg) { 1100 // not found 1101 return 0; 1102 } 1103 methodTypeName = newArg.execute(CheckUTFVisitor.singleton(), null); 1104 1105 // add a new name-and-type for the method 1106 NameAndTypePoolInfo methodNaT = new NameAndTypePoolInfo(methodNameInfo, methodTypeName, cp); 1107 newArg = methodNaT.inPool(cp); 1108 if (null == newArg) { 1109 // not found 1110 return 0; 1111 } 1112 methodNaT = newArg.execute(CheckNameAndTypeVisitor.singleton(), null); 1113 1114 // add a new method info for the method 1115 MethodPoolInfo method = new MethodPoolInfo(monitorClass, methodNaT, cp); 1116 newArg = method.inPool(cp); 1117 if (null == newArg) { 1118 // not found 1119 return 0; 1120 } 1121 method = newArg.execute(CheckMethodVisitor.singleton(), null); 1122 1123 return cp.indexOf(method); 1124 } 1125 }