Mercurial > lasercutter
view src/clojure/asm/ClassWriter.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 /***2 * ASM: a very small and fast Java bytecode manipulation framework3 * Copyright (c) 2000-2005 INRIA, France Telecom4 * All rights reserved.5 *6 * Redistribution and use in source and binary forms, with or without7 * modification, are permitted provided that the following conditions8 * are met:9 * 1. Redistributions of source code must retain the above copyright10 * notice, this list of conditions and the following disclaimer.11 * 2. Redistributions in binary form must reproduce the above copyright12 * notice, this list of conditions and the following disclaimer in the13 * documentation and/or other materials provided with the distribution.14 * 3. Neither the name of the copyright holders nor the names of its15 * contributors may be used to endorse or promote products derived from16 * this software without specific prior written permission.17 *18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF28 * THE POSSIBILITY OF SUCH DAMAGE.29 */30 package clojure.asm;32 /**33 * A {@link ClassVisitor} that generates classes in bytecode form. More34 * precisely this visitor generates a byte array conforming to the Java class35 * file format. It can be used alone, to generate a Java class "from scratch",36 * or with one or more {@link ClassReader ClassReader} and adapter class visitor37 * to generate a modified class from one or more existing Java classes.38 *39 * @author Eric Bruneton40 */41 public class ClassWriter implements ClassVisitor{43 /**44 * Flag to automatically compute the maximum stack size and the maximum45 * number of local variables of methods. If this flag is set, then the46 * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the47 * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod}48 * method will be ignored, and computed automatically from the signature and49 * the bytecode of each method.50 *51 * @see #ClassWriter(int)52 */53 public final static int COMPUTE_MAXS = 1;55 /**56 * Flag to automatically compute the stack map frames of methods from57 * scratch. If this flag is set, then the calls to the58 * {@link MethodVisitor#visitFrame} method are ignored, and the stack map59 * frames are recomputed from the methods bytecode. The arguments of the60 * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and61 * recomputed from the bytecode. In other words, computeFrames implies62 * computeMaxs.63 *64 * @see #ClassWriter(int)65 */66 public final static int COMPUTE_FRAMES = 2;68 /**69 * The type of instructions without any argument.70 */71 final static int NOARG_INSN = 0;73 /**74 * The type of instructions with an signed byte argument.75 */76 final static int SBYTE_INSN = 1;78 /**79 * The type of instructions with an signed short argument.80 */81 final static int SHORT_INSN = 2;83 /**84 * The type of instructions with a local variable index argument.85 */86 final static int VAR_INSN = 3;88 /**89 * The type of instructions with an implicit local variable index argument.90 */91 final static int IMPLVAR_INSN = 4;93 /**94 * The type of instructions with a type descriptor argument.95 */96 final static int TYPE_INSN = 5;98 /**99 * The type of field and method invocations instructions.100 */101 final static int FIELDORMETH_INSN = 6;103 /**104 * The type of the INVOKEINTERFACE instruction.105 */106 final static int ITFMETH_INSN = 7;108 /**109 * The type of instructions with a 2 bytes bytecode offset label.110 */111 final static int LABEL_INSN = 8;113 /**114 * The type of instructions with a 4 bytes bytecode offset label.115 */116 final static int LABELW_INSN = 9;118 /**119 * The type of the LDC instruction.120 */121 final static int LDC_INSN = 10;123 /**124 * The type of the LDC_W and LDC2_W instructions.125 */126 final static int LDCW_INSN = 11;128 /**129 * The type of the IINC instruction.130 */131 final static int IINC_INSN = 12;133 /**134 * The type of the TABLESWITCH instruction.135 */136 final static int TABL_INSN = 13;138 /**139 * The type of the LOOKUPSWITCH instruction.140 */141 final static int LOOK_INSN = 14;143 /**144 * The type of the MULTIANEWARRAY instruction.145 */146 final static int MANA_INSN = 15;148 /**149 * The type of the WIDE instruction.150 */151 final static int WIDE_INSN = 16;153 /**154 * The instruction types of all JVM opcodes.155 */156 static byte[] TYPE;158 /**159 * The type of CONSTANT_Class constant pool items.160 */161 final static int CLASS = 7;163 /**164 * The type of CONSTANT_Fieldref constant pool items.165 */166 final static int FIELD = 9;168 /**169 * The type of CONSTANT_Methodref constant pool items.170 */171 final static int METH = 10;173 /**174 * The type of CONSTANT_InterfaceMethodref constant pool items.175 */176 final static int IMETH = 11;178 /**179 * The type of CONSTANT_String constant pool items.180 */181 final static int STR = 8;183 /**184 * The type of CONSTANT_Integer constant pool items.185 */186 final static int INT = 3;188 /**189 * The type of CONSTANT_Float constant pool items.190 */191 final static int FLOAT = 4;193 /**194 * The type of CONSTANT_Long constant pool items.195 */196 final static int LONG = 5;198 /**199 * The type of CONSTANT_Double constant pool items.200 */201 final static int DOUBLE = 6;203 /**204 * The type of CONSTANT_NameAndType constant pool items.205 */206 final static int NAME_TYPE = 12;208 /**209 * The type of CONSTANT_Utf8 constant pool items.210 */211 final static int UTF8 = 1;213 /**214 * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable},215 * instead of the constant pool, in order to avoid clashes with normal216 * constant pool items in the ClassWriter constant pool's hash table.217 */218 final static int TYPE_NORMAL = 13;220 /**221 * Uninitialized type Item stored in the ClassWriter222 * {@link ClassWriter#typeTable}, instead of the constant pool, in order to223 * avoid clashes with normal constant pool items in the ClassWriter constant224 * pool's hash table.225 */226 final static int TYPE_UNINIT = 14;228 /**229 * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable},230 * instead of the constant pool, in order to avoid clashes with normal231 * constant pool items in the ClassWriter constant pool's hash table.232 */233 final static int TYPE_MERGED = 15;235 /**236 * The class reader from which this class writer was constructed, if any.237 */238 ClassReader cr;240 /**241 * Minor and major version numbers of the class to be generated.242 */243 int version;245 /**246 * Index of the next item to be added in the constant pool.247 */248 int index;250 /**251 * The constant pool of this class.252 */253 ByteVector pool;255 /**256 * The constant pool's hash table data.257 */258 Item[] items;260 /**261 * The threshold of the constant pool's hash table.262 */263 int threshold;265 /**266 * A reusable key used to look for items in the {@link #items} hash table.267 */268 Item key;270 /**271 * A reusable key used to look for items in the {@link #items} hash table.272 */273 Item key2;275 /**276 * A reusable key used to look for items in the {@link #items} hash table.277 */278 Item key3;280 /**281 * A type table used to temporarily store internal names that will not282 * necessarily be stored in the constant pool. This type table is used by283 * the control flow and data flow analysis algorithm used to compute stack284 * map frames from scratch. This array associates to each index <tt>i</tt>285 * the Item whose index is <tt>i</tt>. All Item objects stored in this286 * array are also stored in the {@link #items} hash table. These two arrays287 * allow to retrieve an Item from its index or, conversly, to get the index288 * of an Item from its value. Each Item stores an internal name in its289 * {@link Item#strVal1} field.290 */291 Item[] typeTable;293 /**294 * Number of elements in the {@link #typeTable} array.295 */296 private short typeCount; // TODO int?298 /**299 * The access flags of this class.300 */301 private int access;303 /**304 * The constant pool item that contains the internal name of this class.305 */306 private int name;308 /**309 * The internal name of this class.310 */311 String thisName;313 /**314 * The constant pool item that contains the signature of this class.315 */316 private int signature;318 /**319 * The constant pool item that contains the internal name of the super class320 * of this class.321 */322 private int superName;324 /**325 * Number of interfaces implemented or extended by this class or interface.326 */327 private int interfaceCount;329 /**330 * The interfaces implemented or extended by this class or interface. More331 * precisely, this array contains the indexes of the constant pool items332 * that contain the internal names of these interfaces.333 */334 private int[] interfaces;336 /**337 * The index of the constant pool item that contains the name of the source338 * file from which this class was compiled.339 */340 private int sourceFile;342 /**343 * The SourceDebug attribute of this class.344 */345 private ByteVector sourceDebug;347 /**348 * The constant pool item that contains the name of the enclosing class of349 * this class.350 */351 private int enclosingMethodOwner;353 /**354 * The constant pool item that contains the name and descriptor of the355 * enclosing method of this class.356 */357 private int enclosingMethod;359 /**360 * The runtime visible annotations of this class.361 */362 private AnnotationWriter anns;364 /**365 * The runtime invisible annotations of this class.366 */367 private AnnotationWriter ianns;369 /**370 * The non standard attributes of this class.371 */372 private Attribute attrs;374 /**375 * The number of entries in the InnerClasses attribute.376 */377 private int innerClassesCount;379 /**380 * The InnerClasses attribute.381 */382 private ByteVector innerClasses;384 /**385 * The fields of this class. These fields are stored in a linked list of386 * {@link FieldWriter} objects, linked to each other by their387 * {@link FieldWriter#next} field. This field stores the first element of388 * this list.389 */390 FieldWriter firstField;392 /**393 * The fields of this class. These fields are stored in a linked list of394 * {@link FieldWriter} objects, linked to each other by their395 * {@link FieldWriter#next} field. This field stores the last element of396 * this list.397 */398 FieldWriter lastField;400 /**401 * The methods of this class. These methods are stored in a linked list of402 * {@link MethodWriter} objects, linked to each other by their403 * {@link MethodWriter#next} field. This field stores the first element of404 * this list.405 */406 MethodWriter firstMethod;408 /**409 * The methods of this class. These methods are stored in a linked list of410 * {@link MethodWriter} objects, linked to each other by their411 * {@link MethodWriter#next} field. This field stores the last element of412 * this list.413 */414 MethodWriter lastMethod;416 /**417 * <tt>true</tt> if the maximum stack size and number of local variables418 * must be automatically computed.419 */420 private boolean computeMaxs;422 /**423 * <tt>true</tt> if the stack map frames must be recomputed from scratch.424 */425 private boolean computeFrames;427 /**428 * <tt>true</tt> if the stack map tables of this class are invalid. The429 * {@link MethodWriter#resizeInstructions} method cannot transform existing430 * stack map tables, and so produces potentially invalid classes when it is431 * executed. In this case the class is reread and rewritten with the432 * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize433 * stack map tables when this option is used).434 */435 boolean invalidFrames;437 // ------------------------------------------------------------------------438 // Static initializer439 // ------------------------------------------------------------------------441 /**442 * Computes the instruction types of JVM opcodes.443 */444 static445 {446 int i;447 byte[] b = new byte[220];448 String s = "AAAAAAAAAAAAAAAABCKLLDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"449 + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"450 + "AAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAIIIIIIIIIIIIIIIIDNOAA"451 + "AAAAGGGGGGGHAFBFAAFFAAQPIIJJIIIIIIIIIIIIIIIIII";452 for(i = 0; i < b.length; ++i)453 {454 b[i] = (byte) (s.charAt(i) - 'A');455 }456 TYPE = b;458 // code to generate the above string459 //460 // // SBYTE_INSN instructions461 // b[Constants.NEWARRAY] = SBYTE_INSN;462 // b[Constants.BIPUSH] = SBYTE_INSN;463 //464 // // SHORT_INSN instructions465 // b[Constants.SIPUSH] = SHORT_INSN;466 //467 // // (IMPL)VAR_INSN instructions468 // b[Constants.RET] = VAR_INSN;469 // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) {470 // b[i] = VAR_INSN;471 // }472 // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) {473 // b[i] = VAR_INSN;474 // }475 // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3476 // b[i] = IMPLVAR_INSN;477 // }478 // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3479 // b[i] = IMPLVAR_INSN;480 // }481 //482 // // TYPE_INSN instructions483 // b[Constants.NEW] = TYPE_INSN;484 // b[Constants.ANEWARRAY] = TYPE_INSN;485 // b[Constants.CHECKCAST] = TYPE_INSN;486 // b[Constants.INSTANCEOF] = TYPE_INSN;487 //488 // // (Set)FIELDORMETH_INSN instructions489 // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) {490 // b[i] = FIELDORMETH_INSN;491 // }492 // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN;493 //494 // // LABEL(W)_INSN instructions495 // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) {496 // b[i] = LABEL_INSN;497 // }498 // b[Constants.IFNULL] = LABEL_INSN;499 // b[Constants.IFNONNULL] = LABEL_INSN;500 // b[200] = LABELW_INSN; // GOTO_W501 // b[201] = LABELW_INSN; // JSR_W502 // // temporary opcodes used internally by ASM - see Label and503 // MethodWriter504 // for (i = 202; i < 220; ++i) {505 // b[i] = LABEL_INSN;506 // }507 //508 // // LDC(_W) instructions509 // b[Constants.LDC] = LDC_INSN;510 // b[19] = LDCW_INSN; // LDC_W511 // b[20] = LDCW_INSN; // LDC2_W512 //513 // // special instructions514 // b[Constants.IINC] = IINC_INSN;515 // b[Constants.TABLESWITCH] = TABL_INSN;516 // b[Constants.LOOKUPSWITCH] = LOOK_INSN;517 // b[Constants.MULTIANEWARRAY] = MANA_INSN;518 // b[196] = WIDE_INSN; // WIDE519 //520 // for (i = 0; i < b.length; ++i) {521 // System.err.print((char)('A' + b[i]));522 // }523 // System.err.println();524 }526 // ------------------------------------------------------------------------527 // Constructor528 // ------------------------------------------------------------------------530 /**531 * Constructs a new {@link ClassWriter} object.532 *533 * @param flags option flags that can be used to modify the default behavior534 * of this class. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.535 */536 public ClassWriter(final int flags){537 index = 1;538 pool = new ByteVector();539 items = new Item[256];540 threshold = (int) (0.75d * items.length);541 key = new Item();542 key2 = new Item();543 key3 = new Item();544 this.computeMaxs = (flags & COMPUTE_MAXS) != 0;545 this.computeFrames = (flags & COMPUTE_FRAMES) != 0;546 }548 /**549 * Constructs a new {@link ClassWriter} object and enables optimizations for550 * "mostly add" bytecode transformations. These optimizations are the551 * following:552 * <p/>553 * <ul> <li>The constant pool from the original class is copied as is in554 * the new class, which saves time. New constant pool entries will be added555 * at the end if necessary, but unused constant pool entries <i>won't be556 * removed</i>.</li> <li>Methods that are not transformed are copied as557 * is in the new class, directly from the original class bytecode (i.e.558 * without emitting visit events for all the method instructions), which559 * saves a <i>lot</i> of time. Untransformed methods are detected by the560 * fact that the {@link ClassReader} receives {@link MethodVisitor} objects561 * that come from a {@link ClassWriter} (and not from a custom562 * {@link ClassAdapter} or any other {@link ClassVisitor} instance).</li>563 * </ul>564 *565 * @param classReader the {@link ClassReader} used to read the original566 * class. It will be used to copy the entire constant pool from the567 * original class and also to copy other fragments of original568 * bytecode where applicable.569 * @param flags option flags that can be used to modify the default behavior570 * of this class. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.571 */572 public ClassWriter(final ClassReader classReader, final int flags){573 this(flags);574 classReader.copyPool(this);575 this.cr = classReader;576 }578 // ------------------------------------------------------------------------579 // Implementation of the ClassVisitor interface580 // ------------------------------------------------------------------------582 public void visit(583 final int version,584 final int access,585 final String name,586 final String signature,587 final String superName,588 final String[] interfaces){589 this.version = version;590 this.access = access;591 this.name = newClass(name);592 thisName = name;593 if(signature != null)594 {595 this.signature = newUTF8(signature);596 }597 this.superName = superName == null ? 0 : newClass(superName);598 if(interfaces != null && interfaces.length > 0)599 {600 interfaceCount = interfaces.length;601 this.interfaces = new int[interfaceCount];602 for(int i = 0; i < interfaceCount; ++i)603 {604 this.interfaces[i] = newClass(interfaces[i]);605 }606 }607 }609 public void visitSource(final String file, final String debug){610 if(file != null)611 {612 sourceFile = newUTF8(file);613 }614 if(debug != null)615 {616 sourceDebug = new ByteVector().putUTF8(debug);617 }618 }620 public void visitOuterClass(621 final String owner,622 final String name,623 final String desc){624 enclosingMethodOwner = newClass(owner);625 if(name != null && desc != null)626 {627 enclosingMethod = newNameType(name, desc);628 }629 }631 public AnnotationVisitor visitAnnotation(632 final String desc,633 final boolean visible){634 ByteVector bv = new ByteVector();635 // write type, and reserve space for values count636 bv.putShort(newUTF8(desc)).putShort(0);637 AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2);638 if(visible)639 {640 aw.next = anns;641 anns = aw;642 }643 else644 {645 aw.next = ianns;646 ianns = aw;647 }648 return aw;649 }651 public void visitAttribute(final Attribute attr){652 attr.next = attrs;653 attrs = attr;654 }656 public void visitInnerClass(657 final String name,658 final String outerName,659 final String innerName,660 final int access){661 if(innerClasses == null)662 {663 innerClasses = new ByteVector();664 }665 ++innerClassesCount;666 innerClasses.putShort(name == null ? 0 : newClass(name));667 innerClasses.putShort(outerName == null ? 0 : newClass(outerName));668 innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));669 innerClasses.putShort(access);670 }672 public FieldVisitor visitField(673 final int access,674 final String name,675 final String desc,676 final String signature,677 final Object value){678 return new FieldWriter(this, access, name, desc, signature, value);679 }681 public MethodVisitor visitMethod(682 final int access,683 final String name,684 final String desc,685 final String signature,686 final String[] exceptions){687 return new MethodWriter(this,688 access,689 name,690 desc,691 signature,692 exceptions,693 computeMaxs,694 computeFrames);695 }697 public void visitEnd(){698 }700 // ------------------------------------------------------------------------701 // Other public methods702 // ------------------------------------------------------------------------704 /**705 * Returns the bytecode of the class that was build with this class writer.706 *707 * @return the bytecode of the class that was build with this class writer.708 */709 public byte[] toByteArray(){710 // computes the real size of the bytecode of this class711 int size = 24 + 2 * interfaceCount;712 int nbFields = 0;713 FieldWriter fb = firstField;714 while(fb != null)715 {716 ++nbFields;717 size += fb.getSize();718 fb = fb.next;719 }720 int nbMethods = 0;721 MethodWriter mb = firstMethod;722 while(mb != null)723 {724 ++nbMethods;725 size += mb.getSize();726 mb = mb.next;727 }728 int attributeCount = 0;729 if(signature != 0)730 {731 ++attributeCount;732 size += 8;733 newUTF8("Signature");734 }735 if(sourceFile != 0)736 {737 ++attributeCount;738 size += 8;739 newUTF8("SourceFile");740 }741 if(sourceDebug != null)742 {743 ++attributeCount;744 size += sourceDebug.length + 4;745 newUTF8("SourceDebugExtension");746 }747 if(enclosingMethodOwner != 0)748 {749 ++attributeCount;750 size += 10;751 newUTF8("EnclosingMethod");752 }753 if((access & Opcodes.ACC_DEPRECATED) != 0)754 {755 ++attributeCount;756 size += 6;757 newUTF8("Deprecated");758 }759 if((access & Opcodes.ACC_SYNTHETIC) != 0760 && (version & 0xffff) < Opcodes.V1_5)761 {762 ++attributeCount;763 size += 6;764 newUTF8("Synthetic");765 }766 if(innerClasses != null)767 {768 ++attributeCount;769 size += 8 + innerClasses.length;770 newUTF8("InnerClasses");771 }772 if(anns != null)773 {774 ++attributeCount;775 size += 8 + anns.getSize();776 newUTF8("RuntimeVisibleAnnotations");777 }778 if(ianns != null)779 {780 ++attributeCount;781 size += 8 + ianns.getSize();782 newUTF8("RuntimeInvisibleAnnotations");783 }784 if(attrs != null)785 {786 attributeCount += attrs.getCount();787 size += attrs.getSize(this, null, 0, -1, -1);788 }789 size += pool.length;790 // allocates a byte vector of this size, in order to avoid unnecessary791 // arraycopy operations in the ByteVector.enlarge() method792 ByteVector out = new ByteVector(size);793 out.putInt(0xCAFEBABE).putInt(version);794 out.putShort(index).putByteArray(pool.data, 0, pool.length);795 out.putShort(access).putShort(name).putShort(superName);796 out.putShort(interfaceCount);797 for(int i = 0; i < interfaceCount; ++i)798 {799 out.putShort(interfaces[i]);800 }801 out.putShort(nbFields);802 fb = firstField;803 while(fb != null)804 {805 fb.put(out);806 fb = fb.next;807 }808 out.putShort(nbMethods);809 mb = firstMethod;810 while(mb != null)811 {812 mb.put(out);813 mb = mb.next;814 }815 out.putShort(attributeCount);816 if(signature != 0)817 {818 out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);819 }820 if(sourceFile != 0)821 {822 out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);823 }824 if(sourceDebug != null)825 {826 int len = sourceDebug.length - 2;827 out.putShort(newUTF8("SourceDebugExtension")).putInt(len);828 out.putByteArray(sourceDebug.data, 2, len);829 }830 if(enclosingMethodOwner != 0)831 {832 out.putShort(newUTF8("EnclosingMethod")).putInt(4);833 out.putShort(enclosingMethodOwner).putShort(enclosingMethod);834 }835 if((access & Opcodes.ACC_DEPRECATED) != 0)836 {837 out.putShort(newUTF8("Deprecated")).putInt(0);838 }839 if((access & Opcodes.ACC_SYNTHETIC) != 0840 && (version & 0xffff) < Opcodes.V1_5)841 {842 out.putShort(newUTF8("Synthetic")).putInt(0);843 }844 if(innerClasses != null)845 {846 out.putShort(newUTF8("InnerClasses"));847 out.putInt(innerClasses.length + 2).putShort(innerClassesCount);848 out.putByteArray(innerClasses.data, 0, innerClasses.length);849 }850 if(anns != null)851 {852 out.putShort(newUTF8("RuntimeVisibleAnnotations"));853 anns.put(out);854 }855 if(ianns != null)856 {857 out.putShort(newUTF8("RuntimeInvisibleAnnotations"));858 ianns.put(out);859 }860 if(attrs != null)861 {862 attrs.put(this, null, 0, -1, -1, out);863 }864 if(invalidFrames)865 {866 ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);867 new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES);868 return cw.toByteArray();869 }870 return out.data;871 }873 // ------------------------------------------------------------------------874 // Utility methods: constant pool management875 // ------------------------------------------------------------------------877 /**878 * Adds a number or string constant to the constant pool of the class being879 * build. Does nothing if the constant pool already contains a similar item.880 *881 * @param cst the value of the constant to be added to the constant pool.882 * This parameter must be an {@link Integer}, a {@link Float}, a883 * {@link Long}, a {@link Double}, a {@link String} or a884 * {@link Type}.885 * @return a new or already existing constant item with the given value.886 */887 Item newConstItem(final Object cst){888 if(cst instanceof Integer)889 {890 int val = ((Integer) cst).intValue();891 return newInteger(val);892 }893 else if(cst instanceof Byte)894 {895 int val = ((Byte) cst).intValue();896 return newInteger(val);897 }898 else if(cst instanceof Character)899 {900 int val = ((Character) cst).charValue();901 return newInteger(val);902 }903 else if(cst instanceof Short)904 {905 int val = ((Short) cst).intValue();906 return newInteger(val);907 }908 else if(cst instanceof Boolean)909 {910 int val = ((Boolean) cst).booleanValue() ? 1 : 0;911 return newInteger(val);912 }913 else if(cst instanceof Float)914 {915 float val = ((Float) cst).floatValue();916 return newFloat(val);917 }918 else if(cst instanceof Long)919 {920 long val = ((Long) cst).longValue();921 return newLong(val);922 }923 else if(cst instanceof Double)924 {925 double val = ((Double) cst).doubleValue();926 return newDouble(val);927 }928 else if(cst instanceof String)929 {930 return newString((String) cst);931 }932 else if(cst instanceof Type)933 {934 Type t = (Type) cst;935 return newClassItem(t.getSort() == Type.OBJECT936 ? t.getInternalName()937 : t.getDescriptor());938 }939 else940 {941 throw new IllegalArgumentException("value " + cst);942 }943 }945 /**946 * Adds a number or string constant to the constant pool of the class being947 * build. Does nothing if the constant pool already contains a similar item.948 * <i>This method is intended for {@link Attribute} sub classes, and is949 * normally not needed by class generators or adapters.</i>950 *951 * @param cst the value of the constant to be added to the constant pool.952 * This parameter must be an {@link Integer}, a {@link Float}, a953 * {@link Long}, a {@link Double} or a {@link String}.954 * @return the index of a new or already existing constant item with the955 * given value.956 */957 public int newConst(final Object cst){958 return newConstItem(cst).index;959 }961 /**962 * Adds an UTF8 string to the constant pool of the class being build. Does963 * nothing if the constant pool already contains a similar item. <i>This964 * method is intended for {@link Attribute} sub classes, and is normally not965 * needed by class generators or adapters.</i>966 *967 * @param value the String value.968 * @return the index of a new or already existing UTF8 item.969 */970 public int newUTF8(final String value){971 key.set(UTF8, value, null, null);972 Item result = get(key);973 if(result == null)974 {975 pool.putByte(UTF8).putUTF8(value);976 result = new Item(index++, key);977 put(result);978 }979 return result.index;980 }982 /**983 * Adds a class reference to the constant pool of the class being build.984 * Does nothing if the constant pool already contains a similar item.985 * <i>This method is intended for {@link Attribute} sub classes, and is986 * normally not needed by class generators or adapters.</i>987 *988 * @param value the internal name of the class.989 * @return a new or already existing class reference item.990 */991 Item newClassItem(final String value){992 key2.set(CLASS, value, null, null);993 Item result = get(key2);994 if(result == null)995 {996 pool.put12(CLASS, newUTF8(value));997 result = new Item(index++, key2);998 put(result);999 }1000 return result;1001 }1003 /**1004 * Adds a class reference to the constant pool of the class being build.1005 * Does nothing if the constant pool already contains a similar item.1006 * <i>This method is intended for {@link Attribute} sub classes, and is1007 * normally not needed by class generators or adapters.</i>1008 *1009 * @param value the internal name of the class.1010 * @return the index of a new or already existing class reference item.1011 */1012 public int newClass(final String value){1013 return newClassItem(value).index;1014 }1016 /**1017 * Adds a field reference to the constant pool of the class being build.1018 * Does nothing if the constant pool already contains a similar item.1019 *1020 * @param owner the internal name of the field's owner class.1021 * @param name the field's name.1022 * @param desc the field's descriptor.1023 * @return a new or already existing field reference item.1024 */1025 Item newFieldItem(final String owner, final String name, final String desc){1026 key3.set(FIELD, owner, name, desc);1027 Item result = get(key3);1028 if(result == null)1029 {1030 put122(FIELD, newClass(owner), newNameType(name, desc));1031 result = new Item(index++, key3);1032 put(result);1033 }1034 return result;1035 }1037 /**1038 * Adds a field reference to the constant pool of the class being build.1039 * Does nothing if the constant pool already contains a similar item.1040 * <i>This method is intended for {@link Attribute} sub classes, and is1041 * normally not needed by class generators or adapters.</i>1042 *1043 * @param owner the internal name of the field's owner class.1044 * @param name the field's name.1045 * @param desc the field's descriptor.1046 * @return the index of a new or already existing field reference item.1047 */1048 public int newField(final String owner, final String name, final String desc){1049 return newFieldItem(owner, name, desc).index;1050 }1052 /**1053 * Adds a method reference to the constant pool of the class being build.1054 * Does nothing if the constant pool already contains a similar item.1055 *1056 * @param owner the internal name of the method's owner class.1057 * @param name the method's name.1058 * @param desc the method's descriptor.1059 * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.1060 * @return a new or already existing method reference item.1061 */1062 Item newMethodItem(1063 final String owner,1064 final String name,1065 final String desc,1066 final boolean itf){1067 int type = itf ? IMETH : METH;1068 key3.set(type, owner, name, desc);1069 Item result = get(key3);1070 if(result == null)1071 {1072 put122(type, newClass(owner), newNameType(name, desc));1073 result = new Item(index++, key3);1074 put(result);1075 }1076 return result;1077 }1079 /**1080 * Adds a method reference to the constant pool of the class being build.1081 * Does nothing if the constant pool already contains a similar item.1082 * <i>This method is intended for {@link Attribute} sub classes, and is1083 * normally not needed by class generators or adapters.</i>1084 *1085 * @param owner the internal name of the method's owner class.1086 * @param name the method's name.1087 * @param desc the method's descriptor.1088 * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.1089 * @return the index of a new or already existing method reference item.1090 */1091 public int newMethod(1092 final String owner,1093 final String name,1094 final String desc,1095 final boolean itf){1096 return newMethodItem(owner, name, desc, itf).index;1097 }1099 /**1100 * Adds an integer to the constant pool of the class being build. Does1101 * nothing if the constant pool already contains a similar item.1102 *1103 * @param value the int value.1104 * @return a new or already existing int item.1105 */1106 Item newInteger(final int value){1107 key.set(value);1108 Item result = get(key);1109 if(result == null)1110 {1111 pool.putByte(INT).putInt(value);1112 result = new Item(index++, key);1113 put(result);1114 }1115 return result;1116 }1118 /**1119 * Adds a float to the constant pool of the class being build. Does nothing1120 * if the constant pool already contains a similar item.1121 *1122 * @param value the float value.1123 * @return a new or already existing float item.1124 */1125 Item newFloat(final float value){1126 key.set(value);1127 Item result = get(key);1128 if(result == null)1129 {1130 pool.putByte(FLOAT).putInt(key.intVal);1131 result = new Item(index++, key);1132 put(result);1133 }1134 return result;1135 }1137 /**1138 * Adds a long to the constant pool of the class being build. Does nothing1139 * if the constant pool already contains a similar item.1140 *1141 * @param value the long value.1142 * @return a new or already existing long item.1143 */1144 Item newLong(final long value){1145 key.set(value);1146 Item result = get(key);1147 if(result == null)1148 {1149 pool.putByte(LONG).putLong(value);1150 result = new Item(index, key);1151 put(result);1152 index += 2;1153 }1154 return result;1155 }1157 /**1158 * Adds a double to the constant pool of the class being build. Does nothing1159 * if the constant pool already contains a similar item.1160 *1161 * @param value the double value.1162 * @return a new or already existing double item.1163 */1164 Item newDouble(final double value){1165 key.set(value);1166 Item result = get(key);1167 if(result == null)1168 {1169 pool.putByte(DOUBLE).putLong(key.longVal);1170 result = new Item(index, key);1171 put(result);1172 index += 2;1173 }1174 return result;1175 }1177 /**1178 * Adds a string to the constant pool of the class being build. Does nothing1179 * if the constant pool already contains a similar item.1180 *1181 * @param value the String value.1182 * @return a new or already existing string item.1183 */1184 private Item newString(final String value){1185 key2.set(STR, value, null, null);1186 Item result = get(key2);1187 if(result == null)1188 {1189 pool.put12(STR, newUTF8(value));1190 result = new Item(index++, key2);1191 put(result);1192 }1193 return result;1194 }1196 /**1197 * Adds a name and type to the constant pool of the class being build. Does1198 * nothing if the constant pool already contains a similar item. <i>This1199 * method is intended for {@link Attribute} sub classes, and is normally not1200 * needed by class generators or adapters.</i>1201 *1202 * @param name a name.1203 * @param desc a type descriptor.1204 * @return the index of a new or already existing name and type item.1205 */1206 public int newNameType(final String name, final String desc){1207 key2.set(NAME_TYPE, name, desc, null);1208 Item result = get(key2);1209 if(result == null)1210 {1211 put122(NAME_TYPE, newUTF8(name), newUTF8(desc));1212 result = new Item(index++, key2);1213 put(result);1214 }1215 return result.index;1216 }1218 /**1219 * Adds the given internal name to {@link #typeTable} and returns its index.1220 * Does nothing if the type table already contains this internal name.1221 *1222 * @param type the internal name to be added to the type table.1223 * @return the index of this internal name in the type table.1224 */1225 int addType(final String type){1226 key.set(TYPE_NORMAL, type, null, null);1227 Item result = get(key);1228 if(result == null)1229 {1230 result = addType(key);1231 }1232 return result.index;1233 }1235 /**1236 * Adds the given "uninitialized" type to {@link #typeTable} and returns its1237 * index. This method is used for UNINITIALIZED types, made of an internal1238 * name and a bytecode offset.1239 *1240 * @param type the internal name to be added to the type table.1241 * @param offset the bytecode offset of the NEW instruction that created1242 * this UNINITIALIZED type value.1243 * @return the index of this internal name in the type table.1244 */1245 int addUninitializedType(final String type, final int offset){1246 key.type = TYPE_UNINIT;1247 key.intVal = offset;1248 key.strVal1 = type;1249 key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset);1250 Item result = get(key);1251 if(result == null)1252 {1253 result = addType(key);1254 }1255 return result.index;1256 }1258 /**1259 * Adds the given Item to {@link #typeTable}.1260 *1261 * @param item the value to be added to the type table.1262 * @return the added Item, which a new Item instance with the same value as1263 * the given Item.1264 */1265 private Item addType(final Item item){1266 ++typeCount;1267 Item result = new Item(typeCount, key);1268 put(result);1269 if(typeTable == null)1270 {1271 typeTable = new Item[16];1272 }1273 if(typeCount == typeTable.length)1274 {1275 Item[] newTable = new Item[2 * typeTable.length];1276 System.arraycopy(typeTable, 0, newTable, 0, typeTable.length);1277 typeTable = newTable;1278 }1279 typeTable[typeCount] = result;1280 return result;1281 }1283 /**1284 * Returns the index of the common super type of the two given types. This1285 * method calls {@link #getCommonSuperClass} and caches the result in the1286 * {@link #items} hash table to speedup future calls with the same1287 * parameters.1288 *1289 * @param type1 index of an internal name in {@link #typeTable}.1290 * @param type2 index of an internal name in {@link #typeTable}.1291 * @return the index of the common super type of the two given types.1292 */1293 int getMergedType(final int type1, final int type2){1294 key2.type = TYPE_MERGED;1295 key2.longVal = type1 | (((long) type2) << 32);1296 key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2);1297 Item result = get(key2);1298 if(result == null)1299 {1300 String t = typeTable[type1].strVal1;1301 String u = typeTable[type2].strVal1;1302 key2.intVal = addType(getCommonSuperClass(t, u));1303 result = new Item((short) 0, key2);1304 put(result);1305 }1306 return result.intVal;1307 }1309 /**1310 * Returns the common super type of the two given types. The default1311 * implementation of this method <i>loads<i> the two given classes and uses1312 * the java.lang.Class methods to find the common super class. It can be1313 * overriden to compute this common super type in other ways, in particular1314 * without actually loading any class, or to take into account the class1315 * that is currently being generated by this ClassWriter, which can of1316 * course not be loaded since it is under construction.1317 *1318 * @param type1 the internal name of a class.1319 * @param type2 the internal name of another class.1320 * @return the internal name of the common super class of the two given1321 * classes.1322 */1323 protected String getCommonSuperClass(final String type1, final String type2){1324 Class c, d;1325 try1326 {1327 c = Class.forName(type1.replace('/', '.'));1328 d = Class.forName(type2.replace('/', '.'));1329 }1330 catch(ClassNotFoundException e)1331 {1332 throw new RuntimeException(e);1333 }1334 if(c.isAssignableFrom(d))1335 {1336 return type1;1337 }1338 if(d.isAssignableFrom(c))1339 {1340 return type2;1341 }1342 if(c.isInterface() || d.isInterface())1343 {1344 return "java/lang/Object";1345 }1346 else1347 {1348 do1349 {1350 c = c.getSuperclass();1351 } while(!c.isAssignableFrom(d));1352 return c.getName().replace('.', '/');1353 }1354 }1356 /**1357 * Returns the constant pool's hash table item which is equal to the given1358 * item.1359 *1360 * @param key a constant pool item.1361 * @return the constant pool's hash table item which is equal to the given1362 * item, or <tt>null</tt> if there is no such item.1363 */1364 private Item get(final Item key){1365 Item i = items[key.hashCode % items.length];1366 while(i != null && !key.isEqualTo(i))1367 {1368 i = i.next;1369 }1370 return i;1371 }1373 /**1374 * Puts the given item in the constant pool's hash table. The hash table1375 * <i>must</i> not already contains this item.1376 *1377 * @param i the item to be added to the constant pool's hash table.1378 */1379 private void put(final Item i){1380 if(index > threshold)1381 {1382 int ll = items.length;1383 int nl = ll * 2 + 1;1384 Item[] newItems = new Item[nl];1385 for(int l = ll - 1; l >= 0; --l)1386 {1387 Item j = items[l];1388 while(j != null)1389 {1390 int index = j.hashCode % newItems.length;1391 Item k = j.next;1392 j.next = newItems[index];1393 newItems[index] = j;1394 j = k;1395 }1396 }1397 items = newItems;1398 threshold = (int) (nl * 0.75);1399 }1400 int index = i.hashCode % items.length;1401 i.next = items[index];1402 items[index] = i;1403 }1405 /**1406 * Puts one byte and two shorts into the constant pool.1407 *1408 * @param b a byte.1409 * @param s1 a short.1410 * @param s2 another short.1411 */1412 private void put122(final int b, final int s1, final int s2){1413 pool.put12(b, s1).putShort(s2);1414 }1415 }