0001: /*
0002: * ASM: a very small and fast Java bytecode manipulation framework
0003: * Copyright (c) 2000-2005 INRIA, France Telecom
0004: * All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: * 1. Redistributions of source code must retain the above copyright
0010: * notice, this list of conditions and the following disclaimer.
0011: * 2. Redistributions in binary form must reproduce the above copyright
0012: * notice, this list of conditions and the following disclaimer in the
0013: * documentation and/or other materials provided with the distribution.
0014: * 3. Neither the name of the copyright holders nor the names of its
0015: * contributors may be used to endorse or promote products derived from
0016: * this software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
0028: * THE POSSIBILITY OF SUCH DAMAGE.
0029: */
0030: package org.objectweb.asm;
0031:
0032: /**
0033: * A {@link ClassVisitor} that generates classes in bytecode form. More
0034: * precisely this visitor generates a byte array conforming to the Java class
0035: * file format. It can be used alone, to generate a Java class "from scratch",
0036: * or with one or more {@link ClassReader ClassReader} and adapter class visitor
0037: * to generate a modified class from one or more existing Java classes.
0038: *
0039: * @author Eric Bruneton
0040: */
0041: @SuppressWarnings("unchecked")
0042: public class ClassWriter implements ClassVisitor {
0043:
0044: /**
0045: * Flag to automatically compute the maximum stack size and the maximum
0046: * number of local variables of methods. If this flag is set, then the
0047: * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the
0048: * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod}
0049: * method will be ignored, and computed automatically from the signature and
0050: * the bytecode of each method.
0051: *
0052: * @see #ClassWriter(int)
0053: */
0054: public final static int COMPUTE_MAXS = 1;
0055:
0056: /**
0057: * Flag to automatically compute the stack map frames of methods from
0058: * scratch. If this flag is set, then the calls to the
0059: * {@link MethodVisitor#visitFrame} method are ignored, and the stack map
0060: * frames are recomputed from the methods bytecode. The arguments of the
0061: * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
0062: * recomputed from the bytecode. In other words, computeFrames implies
0063: * computeMaxs.
0064: *
0065: * @see #ClassWriter(int)
0066: */
0067: public final static int COMPUTE_FRAMES = 2;
0068:
0069: /**
0070: * The type of instructions without any argument.
0071: */
0072: final static int NOARG_INSN = 0;
0073:
0074: /**
0075: * The type of instructions with an signed byte argument.
0076: */
0077: final static int SBYTE_INSN = 1;
0078:
0079: /**
0080: * The type of instructions with an signed short argument.
0081: */
0082: final static int SHORT_INSN = 2;
0083:
0084: /**
0085: * The type of instructions with a local variable index argument.
0086: */
0087: final static int VAR_INSN = 3;
0088:
0089: /**
0090: * The type of instructions with an implicit local variable index argument.
0091: */
0092: final static int IMPLVAR_INSN = 4;
0093:
0094: /**
0095: * The type of instructions with a type descriptor argument.
0096: */
0097: final static int TYPE_INSN = 5;
0098:
0099: /**
0100: * The type of field and method invocations instructions.
0101: */
0102: final static int FIELDORMETH_INSN = 6;
0103:
0104: /**
0105: * The type of the INVOKEINTERFACE instruction.
0106: */
0107: final static int ITFMETH_INSN = 7;
0108:
0109: /**
0110: * The type of instructions with a 2 bytes bytecode offset label.
0111: */
0112: final static int LABEL_INSN = 8;
0113:
0114: /**
0115: * The type of instructions with a 4 bytes bytecode offset label.
0116: */
0117: final static int LABELW_INSN = 9;
0118:
0119: /**
0120: * The type of the LDC instruction.
0121: */
0122: final static int LDC_INSN = 10;
0123:
0124: /**
0125: * The type of the LDC_W and LDC2_W instructions.
0126: */
0127: final static int LDCW_INSN = 11;
0128:
0129: /**
0130: * The type of the IINC instruction.
0131: */
0132: final static int IINC_INSN = 12;
0133:
0134: /**
0135: * The type of the TABLESWITCH instruction.
0136: */
0137: final static int TABL_INSN = 13;
0138:
0139: /**
0140: * The type of the LOOKUPSWITCH instruction.
0141: */
0142: final static int LOOK_INSN = 14;
0143:
0144: /**
0145: * The type of the MULTIANEWARRAY instruction.
0146: */
0147: final static int MANA_INSN = 15;
0148:
0149: /**
0150: * The type of the WIDE instruction.
0151: */
0152: final static int WIDE_INSN = 16;
0153:
0154: /**
0155: * The instruction types of all JVM opcodes.
0156: */
0157: static byte[] TYPE;
0158:
0159: /**
0160: * The type of CONSTANT_Class constant pool items.
0161: */
0162: final static int CLASS = 7;
0163:
0164: /**
0165: * The type of CONSTANT_Fieldref constant pool items.
0166: */
0167: final static int FIELD = 9;
0168:
0169: /**
0170: * The type of CONSTANT_Methodref constant pool items.
0171: */
0172: final static int METH = 10;
0173:
0174: /**
0175: * The type of CONSTANT_InterfaceMethodref constant pool items.
0176: */
0177: final static int IMETH = 11;
0178:
0179: /**
0180: * The type of CONSTANT_String constant pool items.
0181: */
0182: final static int STR = 8;
0183:
0184: /**
0185: * The type of CONSTANT_Integer constant pool items.
0186: */
0187: final static int INT = 3;
0188:
0189: /**
0190: * The type of CONSTANT_Float constant pool items.
0191: */
0192: final static int FLOAT = 4;
0193:
0194: /**
0195: * The type of CONSTANT_Long constant pool items.
0196: */
0197: final static int LONG = 5;
0198:
0199: /**
0200: * The type of CONSTANT_Double constant pool items.
0201: */
0202: final static int DOUBLE = 6;
0203:
0204: /**
0205: * The type of CONSTANT_NameAndType constant pool items.
0206: */
0207: final static int NAME_TYPE = 12;
0208:
0209: /**
0210: * The type of CONSTANT_Utf8 constant pool items.
0211: */
0212: final static int UTF8 = 1;
0213:
0214: /**
0215: * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable},
0216: * instead of the constant pool, in order to avoid clashes with normal
0217: * constant pool items in the ClassWriter constant pool's hash table.
0218: */
0219: final static int TYPE_NORMAL = 13;
0220:
0221: /**
0222: * Uninitialized type Item stored in the ClassWriter
0223: * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
0224: * avoid clashes with normal constant pool items in the ClassWriter constant
0225: * pool's hash table.
0226: */
0227: final static int TYPE_UNINIT = 14;
0228:
0229: /**
0230: * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable},
0231: * instead of the constant pool, in order to avoid clashes with normal
0232: * constant pool items in the ClassWriter constant pool's hash table.
0233: */
0234: final static int TYPE_MERGED = 15;
0235:
0236: /**
0237: * The class reader from which this class writer was constructed, if any.
0238: */
0239: ClassReader cr;
0240:
0241: /**
0242: * Minor and major version numbers of the class to be generated.
0243: */
0244: int version;
0245:
0246: /**
0247: * Index of the next item to be added in the constant pool.
0248: */
0249: int index;
0250:
0251: /**
0252: * The constant pool of this class.
0253: */
0254: ByteVector pool;
0255:
0256: /**
0257: * The constant pool's hash table data.
0258: */
0259: Item[] items;
0260:
0261: /**
0262: * The threshold of the constant pool's hash table.
0263: */
0264: int threshold;
0265:
0266: /**
0267: * A reusable key used to look for items in the {@link #items} hash table.
0268: */
0269: Item key;
0270:
0271: /**
0272: * A reusable key used to look for items in the {@link #items} hash table.
0273: */
0274: Item key2;
0275:
0276: /**
0277: * A reusable key used to look for items in the {@link #items} hash table.
0278: */
0279: Item key3;
0280:
0281: /**
0282: * A type table used to temporarily store internal names that will not
0283: * necessarily be stored in the constant pool. This type table is used by
0284: * the control flow and data flow analysis algorithm used to compute stack
0285: * map frames from scratch. This array associates to each index <tt>i</tt>
0286: * the Item whose index is <tt>i</tt>. All Item objects stored in this
0287: * array are also stored in the {@link #items} hash table. These two arrays
0288: * allow to retrieve an Item from its index or, conversly, to get the index
0289: * of an Item from its value. Each Item stores an internal name in its
0290: * {@link Item#strVal1} field.
0291: */
0292: Item[] typeTable;
0293:
0294: /**
0295: * Number of elements in the {@link #typeTable} array.
0296: */
0297: private short typeCount; // TODO int?
0298:
0299: /**
0300: * The access flags of this class.
0301: */
0302: private int access;
0303:
0304: /**
0305: * The constant pool item that contains the internal name of this class.
0306: */
0307: private int name;
0308:
0309: /**
0310: * The internal name of this class.
0311: */
0312: String this Name;
0313:
0314: /**
0315: * The constant pool item that contains the signature of this class.
0316: */
0317: private int signature;
0318:
0319: /**
0320: * The constant pool item that contains the internal name of the super class
0321: * of this class.
0322: */
0323: private int super Name;
0324:
0325: /**
0326: * Number of interfaces implemented or extended by this class or interface.
0327: */
0328: private int interfaceCount;
0329:
0330: /**
0331: * The interfaces implemented or extended by this class or interface. More
0332: * precisely, this array contains the indexes of the constant pool items
0333: * that contain the internal names of these interfaces.
0334: */
0335: private int[] interfaces;
0336:
0337: /**
0338: * The index of the constant pool item that contains the name of the source
0339: * file from which this class was compiled.
0340: */
0341: private int sourceFile;
0342:
0343: /**
0344: * The SourceDebug attribute of this class.
0345: */
0346: private ByteVector sourceDebug;
0347:
0348: /**
0349: * The constant pool item that contains the name of the enclosing class of
0350: * this class.
0351: */
0352: private int enclosingMethodOwner;
0353:
0354: /**
0355: * The constant pool item that contains the name and descriptor of the
0356: * enclosing method of this class.
0357: */
0358: private int enclosingMethod;
0359:
0360: /**
0361: * The runtime visible annotations of this class.
0362: */
0363: private AnnotationWriter anns;
0364:
0365: /**
0366: * The runtime invisible annotations of this class.
0367: */
0368: private AnnotationWriter ianns;
0369:
0370: /**
0371: * The non standard attributes of this class.
0372: */
0373: private Attribute attrs;
0374:
0375: /**
0376: * The number of entries in the InnerClasses attribute.
0377: */
0378: private int innerClassesCount;
0379:
0380: /**
0381: * The InnerClasses attribute.
0382: */
0383: private ByteVector innerClasses;
0384:
0385: /**
0386: * The fields of this class. These fields are stored in a linked list of
0387: * {@link FieldWriter} objects, linked to each other by their
0388: * {@link FieldWriter#next} field. This field stores the first element of
0389: * this list.
0390: */
0391: FieldWriter firstField;
0392:
0393: /**
0394: * The fields of this class. These fields are stored in a linked list of
0395: * {@link FieldWriter} objects, linked to each other by their
0396: * {@link FieldWriter#next} field. This field stores the last element of
0397: * this list.
0398: */
0399: FieldWriter lastField;
0400:
0401: /**
0402: * The methods of this class. These methods are stored in a linked list of
0403: * {@link MethodWriter} objects, linked to each other by their
0404: * {@link MethodWriter#next} field. This field stores the first element of
0405: * this list.
0406: */
0407: MethodWriter firstMethod;
0408:
0409: /**
0410: * The methods of this class. These methods are stored in a linked list of
0411: * {@link MethodWriter} objects, linked to each other by their
0412: * {@link MethodWriter#next} field. This field stores the last element of
0413: * this list.
0414: */
0415: MethodWriter lastMethod;
0416:
0417: /**
0418: * <tt>true</tt> if the maximum stack size and number of local variables
0419: * must be automatically computed.
0420: */
0421: private boolean computeMaxs;
0422:
0423: /**
0424: * <tt>true</tt> if the stack map frames must be recomputed from scratch.
0425: */
0426: private boolean computeFrames;
0427:
0428: /**
0429: * <tt>true</tt> if the stack map tables of this class are invalid. The
0430: * {@link MethodWriter#resizeInstructions} method cannot transform existing
0431: * stack map tables, and so produces potentially invalid classes when it is
0432: * executed. In this case the class is reread and rewritten with the
0433: * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize
0434: * stack map tables when this option is used).
0435: */
0436: boolean invalidFrames;
0437:
0438: // ------------------------------------------------------------------------
0439: // Static initializer
0440: // ------------------------------------------------------------------------
0441:
0442: /**
0443: * Computes the instruction types of JVM opcodes.
0444: */
0445: static {
0446: int i;
0447: byte[] b = new byte[220];
0448: String s = "AAAAAAAAAAAAAAAABCKLLDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
0449: + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
0450: + "AAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAIIIIIIIIIIIIIIIIDNOAA"
0451: + "AAAAGGGGGGGHAFBFAAFFAAQPIIJJIIIIIIIIIIIIIIIIII";
0452: for (i = 0; i < b.length; ++i) {
0453: b[i] = (byte) (s.charAt(i) - 'A');
0454: }
0455: TYPE = b;
0456:
0457: // code to generate the above string
0458: //
0459: // // SBYTE_INSN instructions
0460: // b[Constants.NEWARRAY] = SBYTE_INSN;
0461: // b[Constants.BIPUSH] = SBYTE_INSN;
0462: //
0463: // // SHORT_INSN instructions
0464: // b[Constants.SIPUSH] = SHORT_INSN;
0465: //
0466: // // (IMPL)VAR_INSN instructions
0467: // b[Constants.RET] = VAR_INSN;
0468: // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) {
0469: // b[i] = VAR_INSN;
0470: // }
0471: // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) {
0472: // b[i] = VAR_INSN;
0473: // }
0474: // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3
0475: // b[i] = IMPLVAR_INSN;
0476: // }
0477: // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3
0478: // b[i] = IMPLVAR_INSN;
0479: // }
0480: //
0481: // // TYPE_INSN instructions
0482: // b[Constants.NEW] = TYPE_INSN;
0483: // b[Constants.ANEWARRAY] = TYPE_INSN;
0484: // b[Constants.CHECKCAST] = TYPE_INSN;
0485: // b[Constants.INSTANCEOF] = TYPE_INSN;
0486: //
0487: // // (Set)FIELDORMETH_INSN instructions
0488: // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) {
0489: // b[i] = FIELDORMETH_INSN;
0490: // }
0491: // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN;
0492: //
0493: // // LABEL(W)_INSN instructions
0494: // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) {
0495: // b[i] = LABEL_INSN;
0496: // }
0497: // b[Constants.IFNULL] = LABEL_INSN;
0498: // b[Constants.IFNONNULL] = LABEL_INSN;
0499: // b[200] = LABELW_INSN; // GOTO_W
0500: // b[201] = LABELW_INSN; // JSR_W
0501: // // temporary opcodes used internally by ASM - see Label and
0502: // MethodWriter
0503: // for (i = 202; i < 220; ++i) {
0504: // b[i] = LABEL_INSN;
0505: // }
0506: //
0507: // // LDC(_W) instructions
0508: // b[Constants.LDC] = LDC_INSN;
0509: // b[19] = LDCW_INSN; // LDC_W
0510: // b[20] = LDCW_INSN; // LDC2_W
0511: //
0512: // // special instructions
0513: // b[Constants.IINC] = IINC_INSN;
0514: // b[Constants.TABLESWITCH] = TABL_INSN;
0515: // b[Constants.LOOKUPSWITCH] = LOOK_INSN;
0516: // b[Constants.MULTIANEWARRAY] = MANA_INSN;
0517: // b[196] = WIDE_INSN; // WIDE
0518: //
0519: // for (i = 0; i < b.length; ++i) {
0520: // System.err.print((char)('A' + b[i]));
0521: // }
0522: // System.err.println();
0523: }
0524:
0525: // ------------------------------------------------------------------------
0526: // Constructor
0527: // ------------------------------------------------------------------------
0528:
0529: /**
0530: * Constructs a new {@link ClassWriter} object.
0531: *
0532: * @param flags option flags that can be used to modify the default behavior
0533: * of this class. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.
0534: */
0535: public ClassWriter(final int flags) {
0536: index = 1;
0537: pool = new ByteVector();
0538: items = new Item[256];
0539: threshold = (int) (0.75d * items.length);
0540: key = new Item();
0541: key2 = new Item();
0542: key3 = new Item();
0543: this .computeMaxs = (flags & COMPUTE_MAXS) != 0;
0544: this .computeFrames = (flags & COMPUTE_FRAMES) != 0;
0545: }
0546:
0547: /**
0548: * Constructs a new {@link ClassWriter} object and enables optimizations for
0549: * "mostly add" bytecode transformations. These optimizations are the
0550: * following:
0551: *
0552: * <ul> <li>The constant pool from the original class is copied as is in
0553: * the new class, which saves time. New constant pool entries will be added
0554: * at the end if necessary, but unused constant pool entries <i>won't be
0555: * removed</i>.</li> <li>Methods that are not transformed are copied as
0556: * is in the new class, directly from the original class bytecode (i.e.
0557: * without emitting visit events for all the method instructions), which
0558: * saves a <i>lot</i> of time. Untransformed methods are detected by the
0559: * fact that the {@link ClassReader} receives {@link MethodVisitor} objects
0560: * that come from a {@link ClassWriter} (and not from a custom
0561: * {@link ClassAdapter} or any other {@link ClassVisitor} instance).</li>
0562: * </ul>
0563: *
0564: * @param classReader the {@link ClassReader} used to read the original
0565: * class. It will be used to copy the entire constant pool from the
0566: * original class and also to copy other fragments of original
0567: * bytecode where applicable.
0568: * @param flags option flags that can be used to modify the default behavior
0569: * of this class. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.
0570: */
0571: public ClassWriter(final ClassReader classReader, final int flags) {
0572: this (flags);
0573: classReader.copyPool(this );
0574: this .cr = classReader;
0575: }
0576:
0577: // ------------------------------------------------------------------------
0578: // Implementation of the ClassVisitor interface
0579: // ------------------------------------------------------------------------
0580:
0581: public void visit(final int version, final int access,
0582: final String name, final String signature,
0583: final String super Name, final String[] interfaces) {
0584: this .version = version;
0585: this .access = access;
0586: this .name = newClass(name);
0587: this Name = name;
0588: if (signature != null) {
0589: this .signature = newUTF8(signature);
0590: }
0591: this .super Name = super Name == null ? 0 : newClass(super Name);
0592: if (interfaces != null && interfaces.length > 0) {
0593: interfaceCount = interfaces.length;
0594: this .interfaces = new int[interfaceCount];
0595: for (int i = 0; i < interfaceCount; ++i) {
0596: this .interfaces[i] = newClass(interfaces[i]);
0597: }
0598: }
0599: }
0600:
0601: public void visitSource(final String file, final String debug) {
0602: if (file != null) {
0603: sourceFile = newUTF8(file);
0604: }
0605: if (debug != null) {
0606: sourceDebug = new ByteVector().putUTF8(debug);
0607: }
0608: }
0609:
0610: public void visitOuterClass(final String owner, final String name,
0611: final String desc) {
0612: enclosingMethodOwner = newClass(owner);
0613: if (name != null && desc != null) {
0614: enclosingMethod = newNameType(name, desc);
0615: }
0616: }
0617:
0618: public AnnotationVisitor visitAnnotation(final String desc,
0619: final boolean visible) {
0620: ByteVector bv = new ByteVector();
0621: // write type, and reserve space for values count
0622: bv.putShort(newUTF8(desc)).putShort(0);
0623: AnnotationWriter aw = new AnnotationWriter(this , true, bv, bv,
0624: 2);
0625: if (visible) {
0626: aw.next = anns;
0627: anns = aw;
0628: } else {
0629: aw.next = ianns;
0630: ianns = aw;
0631: }
0632: return aw;
0633: }
0634:
0635: public void visitAttribute(final Attribute attr) {
0636: attr.next = attrs;
0637: attrs = attr;
0638: }
0639:
0640: public void visitInnerClass(final String name,
0641: final String outerName, final String innerName,
0642: final int access) {
0643: if (innerClasses == null) {
0644: innerClasses = new ByteVector();
0645: }
0646: ++innerClassesCount;
0647: innerClasses.putShort(name == null ? 0 : newClass(name));
0648: innerClasses.putShort(outerName == null ? 0
0649: : newClass(outerName));
0650: innerClasses.putShort(innerName == null ? 0
0651: : newUTF8(innerName));
0652: innerClasses.putShort(access);
0653: }
0654:
0655: public FieldVisitor visitField(final int access, final String name,
0656: final String desc, final String signature,
0657: final Object value) {
0658: return new FieldWriter(this , access, name, desc, signature,
0659: value);
0660: }
0661:
0662: public MethodVisitor visitMethod(final int access,
0663: final String name, final String desc,
0664: final String signature, final String[] exceptions) {
0665: return new MethodWriter(this , access, name, desc, signature,
0666: exceptions, computeMaxs, computeFrames);
0667: }
0668:
0669: public void visitEnd() {
0670: }
0671:
0672: // ------------------------------------------------------------------------
0673: // Other public methods
0674: // ------------------------------------------------------------------------
0675:
0676: /**
0677: * Returns the bytecode of the class that was build with this class writer.
0678: *
0679: * @return the bytecode of the class that was build with this class writer.
0680: */
0681: public byte[] toByteArray() {
0682: // computes the real size of the bytecode of this class
0683: int size = 24 + 2 * interfaceCount;
0684: int nbFields = 0;
0685: FieldWriter fb = firstField;
0686: while (fb != null) {
0687: ++nbFields;
0688: size += fb.getSize();
0689: fb = fb.next;
0690: }
0691: int nbMethods = 0;
0692: MethodWriter mb = firstMethod;
0693: while (mb != null) {
0694: ++nbMethods;
0695: size += mb.getSize();
0696: mb = mb.next;
0697: }
0698: int attributeCount = 0;
0699: if (signature != 0) {
0700: ++attributeCount;
0701: size += 8;
0702: newUTF8("Signature");
0703: }
0704: if (sourceFile != 0) {
0705: ++attributeCount;
0706: size += 8;
0707: newUTF8("SourceFile");
0708: }
0709: if (sourceDebug != null) {
0710: ++attributeCount;
0711: size += sourceDebug.length + 4;
0712: newUTF8("SourceDebugExtension");
0713: }
0714: if (enclosingMethodOwner != 0) {
0715: ++attributeCount;
0716: size += 10;
0717: newUTF8("EnclosingMethod");
0718: }
0719: if ((access & Opcodes.ACC_DEPRECATED) != 0) {
0720: ++attributeCount;
0721: size += 6;
0722: newUTF8("Deprecated");
0723: }
0724: if ((access & Opcodes.ACC_SYNTHETIC) != 0
0725: && (version & 0xffff) < Opcodes.V1_5) {
0726: ++attributeCount;
0727: size += 6;
0728: newUTF8("Synthetic");
0729: }
0730: if (innerClasses != null) {
0731: ++attributeCount;
0732: size += 8 + innerClasses.length;
0733: newUTF8("InnerClasses");
0734: }
0735: if (anns != null) {
0736: ++attributeCount;
0737: size += 8 + anns.getSize();
0738: newUTF8("RuntimeVisibleAnnotations");
0739: }
0740: if (ianns != null) {
0741: ++attributeCount;
0742: size += 8 + ianns.getSize();
0743: newUTF8("RuntimeInvisibleAnnotations");
0744: }
0745: if (attrs != null) {
0746: attributeCount += attrs.getCount();
0747: size += attrs.getSize(this , null, 0, -1, -1);
0748: }
0749: size += pool.length;
0750: // allocates a byte vector of this size, in order to avoid unnecessary
0751: // arraycopy operations in the ByteVector.enlarge() method
0752: ByteVector out = new ByteVector(size);
0753: out.putInt(0xCAFEBABE).putInt(version);
0754: out.putShort(index).putByteArray(pool.data, 0, pool.length);
0755: out.putShort(access).putShort(name).putShort(super Name);
0756: out.putShort(interfaceCount);
0757: for (int i = 0; i < interfaceCount; ++i) {
0758: out.putShort(interfaces[i]);
0759: }
0760: out.putShort(nbFields);
0761: fb = firstField;
0762: while (fb != null) {
0763: fb.put(out);
0764: fb = fb.next;
0765: }
0766: out.putShort(nbMethods);
0767: mb = firstMethod;
0768: while (mb != null) {
0769: mb.put(out);
0770: mb = mb.next;
0771: }
0772: out.putShort(attributeCount);
0773: if (signature != 0) {
0774: out.putShort(newUTF8("Signature")).putInt(2).putShort(
0775: signature);
0776: }
0777: if (sourceFile != 0) {
0778: out.putShort(newUTF8("SourceFile")).putInt(2).putShort(
0779: sourceFile);
0780: }
0781: if (sourceDebug != null) {
0782: int len = sourceDebug.length - 2;
0783: out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
0784: out.putByteArray(sourceDebug.data, 2, len);
0785: }
0786: if (enclosingMethodOwner != 0) {
0787: out.putShort(newUTF8("EnclosingMethod")).putInt(4);
0788: out.putShort(enclosingMethodOwner)
0789: .putShort(enclosingMethod);
0790: }
0791: if ((access & Opcodes.ACC_DEPRECATED) != 0) {
0792: out.putShort(newUTF8("Deprecated")).putInt(0);
0793: }
0794: if ((access & Opcodes.ACC_SYNTHETIC) != 0
0795: && (version & 0xffff) < Opcodes.V1_5) {
0796: out.putShort(newUTF8("Synthetic")).putInt(0);
0797: }
0798: if (innerClasses != null) {
0799: out.putShort(newUTF8("InnerClasses"));
0800: out.putInt(innerClasses.length + 2).putShort(
0801: innerClassesCount);
0802: out.putByteArray(innerClasses.data, 0, innerClasses.length);
0803: }
0804: if (anns != null) {
0805: out.putShort(newUTF8("RuntimeVisibleAnnotations"));
0806: anns.put(out);
0807: }
0808: if (ianns != null) {
0809: out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
0810: ianns.put(out);
0811: }
0812: if (attrs != null) {
0813: attrs.put(this , null, 0, -1, -1, out);
0814: }
0815: if (invalidFrames) {
0816: ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
0817: new ClassReader(out.data).accept(cw,
0818: ClassReader.SKIP_FRAMES);
0819: return cw.toByteArray();
0820: }
0821: return out.data;
0822: }
0823:
0824: // ------------------------------------------------------------------------
0825: // Utility methods: constant pool management
0826: // ------------------------------------------------------------------------
0827:
0828: /**
0829: * Adds a number or string constant to the constant pool of the class being
0830: * build. Does nothing if the constant pool already contains a similar item.
0831: *
0832: * @param cst the value of the constant to be added to the constant pool.
0833: * This parameter must be an {@link Integer}, a {@link Float}, a
0834: * {@link Long}, a {@link Double}, a {@link String} or a
0835: * {@link Type}.
0836: * @return a new or already existing constant item with the given value.
0837: */
0838: Item newConstItem(final Object cst) {
0839: if (cst instanceof Integer) {
0840: int val = ((Integer) cst).intValue();
0841: return newInteger(val);
0842: } else if (cst instanceof Byte) {
0843: int val = ((Byte) cst).intValue();
0844: return newInteger(val);
0845: } else if (cst instanceof Character) {
0846: int val = ((Character) cst).charValue();
0847: return newInteger(val);
0848: } else if (cst instanceof Short) {
0849: int val = ((Short) cst).intValue();
0850: return newInteger(val);
0851: } else if (cst instanceof Boolean) {
0852: int val = ((Boolean) cst).booleanValue() ? 1 : 0;
0853: return newInteger(val);
0854: } else if (cst instanceof Float) {
0855: float val = ((Float) cst).floatValue();
0856: return newFloat(val);
0857: } else if (cst instanceof Long) {
0858: long val = ((Long) cst).longValue();
0859: return newLong(val);
0860: } else if (cst instanceof Double) {
0861: double val = ((Double) cst).doubleValue();
0862: return newDouble(val);
0863: } else if (cst instanceof String) {
0864: return newString((String) cst);
0865: } else if (cst instanceof Type) {
0866: Type t = (Type) cst;
0867: return newClassItem(t.getSort() == Type.OBJECT ? t
0868: .getInternalName() : t.getDescriptor());
0869: } else {
0870: throw new IllegalArgumentException("value " + cst);
0871: }
0872: }
0873:
0874: /**
0875: * Adds a number or string constant to the constant pool of the class being
0876: * build. Does nothing if the constant pool already contains a similar item.
0877: * <i>This method is intended for {@link Attribute} sub classes, and is
0878: * normally not needed by class generators or adapters.</i>
0879: *
0880: * @param cst the value of the constant to be added to the constant pool.
0881: * This parameter must be an {@link Integer}, a {@link Float}, a
0882: * {@link Long}, a {@link Double} or a {@link String}.
0883: * @return the index of a new or already existing constant item with the
0884: * given value.
0885: */
0886: public int newConst(final Object cst) {
0887: return newConstItem(cst).index;
0888: }
0889:
0890: /**
0891: * Adds an UTF8 string to the constant pool of the class being build. Does
0892: * nothing if the constant pool already contains a similar item. <i>This
0893: * method is intended for {@link Attribute} sub classes, and is normally not
0894: * needed by class generators or adapters.</i>
0895: *
0896: * @param value the String value.
0897: * @return the index of a new or already existing UTF8 item.
0898: */
0899: public int newUTF8(final String value) {
0900: key.set(UTF8, value, null, null);
0901: Item result = get(key);
0902: if (result == null) {
0903: pool.putByte(UTF8).putUTF8(value);
0904: result = new Item(index++, key);
0905: put(result);
0906: }
0907: return result.index;
0908: }
0909:
0910: /**
0911: * Adds a class reference to the constant pool of the class being build.
0912: * Does nothing if the constant pool already contains a similar item.
0913: * <i>This method is intended for {@link Attribute} sub classes, and is
0914: * normally not needed by class generators or adapters.</i>
0915: *
0916: * @param value the internal name of the class.
0917: * @return a new or already existing class reference item.
0918: */
0919: Item newClassItem(final String value) {
0920: key2.set(CLASS, value, null, null);
0921: Item result = get(key2);
0922: if (result == null) {
0923: pool.put12(CLASS, newUTF8(value));
0924: result = new Item(index++, key2);
0925: put(result);
0926: }
0927: return result;
0928: }
0929:
0930: /**
0931: * Adds a class reference to the constant pool of the class being build.
0932: * Does nothing if the constant pool already contains a similar item.
0933: * <i>This method is intended for {@link Attribute} sub classes, and is
0934: * normally not needed by class generators or adapters.</i>
0935: *
0936: * @param value the internal name of the class.
0937: * @return the index of a new or already existing class reference item.
0938: */
0939: public int newClass(final String value) {
0940: return newClassItem(value).index;
0941: }
0942:
0943: /**
0944: * Adds a field reference to the constant pool of the class being build.
0945: * Does nothing if the constant pool already contains a similar item.
0946: *
0947: * @param owner the internal name of the field's owner class.
0948: * @param name the field's name.
0949: * @param desc the field's descriptor.
0950: * @return a new or already existing field reference item.
0951: */
0952: Item newFieldItem(final String owner, final String name,
0953: final String desc) {
0954: key3.set(FIELD, owner, name, desc);
0955: Item result = get(key3);
0956: if (result == null) {
0957: put122(FIELD, newClass(owner), newNameType(name, desc));
0958: result = new Item(index++, key3);
0959: put(result);
0960: }
0961: return result;
0962: }
0963:
0964: /**
0965: * Adds a field reference to the constant pool of the class being build.
0966: * Does nothing if the constant pool already contains a similar item.
0967: * <i>This method is intended for {@link Attribute} sub classes, and is
0968: * normally not needed by class generators or adapters.</i>
0969: *
0970: * @param owner the internal name of the field's owner class.
0971: * @param name the field's name.
0972: * @param desc the field's descriptor.
0973: * @return the index of a new or already existing field reference item.
0974: */
0975: public int newField(final String owner, final String name,
0976: final String desc) {
0977: return newFieldItem(owner, name, desc).index;
0978: }
0979:
0980: /**
0981: * Adds a method reference to the constant pool of the class being build.
0982: * Does nothing if the constant pool already contains a similar item.
0983: *
0984: * @param owner the internal name of the method's owner class.
0985: * @param name the method's name.
0986: * @param desc the method's descriptor.
0987: * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.
0988: * @return a new or already existing method reference item.
0989: */
0990: Item newMethodItem(final String owner, final String name,
0991: final String desc, final boolean itf) {
0992: int type = itf ? IMETH : METH;
0993: key3.set(type, owner, name, desc);
0994: Item result = get(key3);
0995: if (result == null) {
0996: put122(type, newClass(owner), newNameType(name, desc));
0997: result = new Item(index++, key3);
0998: put(result);
0999: }
1000: return result;
1001: }
1002:
1003: /**
1004: * Adds a method 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 is
1007: * normally not needed by class generators or adapters.</i>
1008: *
1009: * @param owner the internal name of the method's owner class.
1010: * @param name the method's name.
1011: * @param desc the method's descriptor.
1012: * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.
1013: * @return the index of a new or already existing method reference item.
1014: */
1015: public int newMethod(final String owner, final String name,
1016: final String desc, final boolean itf) {
1017: return newMethodItem(owner, name, desc, itf).index;
1018: }
1019:
1020: /**
1021: * Adds an integer to the constant pool of the class being build. Does
1022: * nothing if the constant pool already contains a similar item.
1023: *
1024: * @param value the int value.
1025: * @return a new or already existing int item.
1026: */
1027: Item newInteger(final int value) {
1028: key.set(value);
1029: Item result = get(key);
1030: if (result == null) {
1031: pool.putByte(INT).putInt(value);
1032: result = new Item(index++, key);
1033: put(result);
1034: }
1035: return result;
1036: }
1037:
1038: /**
1039: * Adds a float to the constant pool of the class being build. Does nothing
1040: * if the constant pool already contains a similar item.
1041: *
1042: * @param value the float value.
1043: * @return a new or already existing float item.
1044: */
1045: Item newFloat(final float value) {
1046: key.set(value);
1047: Item result = get(key);
1048: if (result == null) {
1049: pool.putByte(FLOAT).putInt(Float.floatToIntBits(value));
1050: result = new Item(index++, key);
1051: put(result);
1052: }
1053: return result;
1054: }
1055:
1056: /**
1057: * Adds a long to the constant pool of the class being build. Does nothing
1058: * if the constant pool already contains a similar item.
1059: *
1060: * @param value the long value.
1061: * @return a new or already existing long item.
1062: */
1063: Item newLong(final long value) {
1064: key.set(value);
1065: Item result = get(key);
1066: if (result == null) {
1067: pool.putByte(LONG).putLong(value);
1068: result = new Item(index, key);
1069: put(result);
1070: index += 2;
1071: }
1072: return result;
1073: }
1074:
1075: /**
1076: * Adds a double to the constant pool of the class being build. Does nothing
1077: * if the constant pool already contains a similar item.
1078: *
1079: * @param value the double value.
1080: * @return a new or already existing double item.
1081: */
1082: Item newDouble(final double value) {
1083: key.set(value);
1084: Item result = get(key);
1085: if (result == null) {
1086: pool.putByte(DOUBLE)
1087: .putLong(Double.doubleToLongBits(value));
1088: result = new Item(index, key);
1089: put(result);
1090: index += 2;
1091: }
1092: return result;
1093: }
1094:
1095: /**
1096: * Adds a string to the constant pool of the class being build. Does nothing
1097: * if the constant pool already contains a similar item.
1098: *
1099: * @param value the String value.
1100: * @return a new or already existing string item.
1101: */
1102: private Item newString(final String value) {
1103: key2.set(STR, value, null, null);
1104: Item result = get(key2);
1105: if (result == null) {
1106: pool.put12(STR, newUTF8(value));
1107: result = new Item(index++, key2);
1108: put(result);
1109: }
1110: return result;
1111: }
1112:
1113: /**
1114: * Adds a name and type to the constant pool of the class being build. Does
1115: * nothing if the constant pool already contains a similar item. <i>This
1116: * method is intended for {@link Attribute} sub classes, and is normally not
1117: * needed by class generators or adapters.</i>
1118: *
1119: * @param name a name.
1120: * @param desc a type descriptor.
1121: * @return the index of a new or already existing name and type item.
1122: */
1123: public int newNameType(final String name, final String desc) {
1124: key2.set(NAME_TYPE, name, desc, null);
1125: Item result = get(key2);
1126: if (result == null) {
1127: put122(NAME_TYPE, newUTF8(name), newUTF8(desc));
1128: result = new Item(index++, key2);
1129: put(result);
1130: }
1131: return result.index;
1132: }
1133:
1134: /**
1135: * Adds the given internal name to {@link #typeTable} and returns its index.
1136: * Does nothing if the type table already contains this internal name.
1137: *
1138: * @param type the internal name to be added to the type table.
1139: * @return the index of this internal name in the type table.
1140: */
1141: int addType(final String type) {
1142: key.set(TYPE_NORMAL, type, null, null);
1143: Item result = get(key);
1144: if (result == null) {
1145: result = addType(key);
1146: }
1147: return result.index;
1148: }
1149:
1150: /**
1151: * Adds the given "uninitialized" type to {@link #typeTable} and returns its
1152: * index. This method is used for UNINITIALIZED types, made of an internal
1153: * name and a bytecode offset.
1154: *
1155: * @param type the internal name to be added to the type table.
1156: * @param offset the bytecode offset of the NEW instruction that created
1157: * this UNINITIALIZED type value.
1158: * @return the index of this internal name in the type table.
1159: */
1160: int addUninitializedType(final String type, final int offset) {
1161: key.type = TYPE_UNINIT;
1162: key.intVal = offset;
1163: key.strVal1 = type;
1164: key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset);
1165: Item result = get(key);
1166: if (result == null) {
1167: result = addType(key);
1168: }
1169: return result.index;
1170: }
1171:
1172: /**
1173: * Adds the given Item to {@link #typeTable}.
1174: *
1175: * @param item the value to be added to the type table.
1176: * @return the added Item, which a new Item instance with the same value as
1177: * the given Item.
1178: */
1179: private Item addType(final Item item) {
1180: ++typeCount;
1181: Item result = new Item(typeCount, key);
1182: put(result);
1183: if (typeTable == null) {
1184: typeTable = new Item[16];
1185: }
1186: if (typeCount == typeTable.length) {
1187: Item[] newTable = new Item[2 * typeTable.length];
1188: System.arraycopy(typeTable, 0, newTable, 0,
1189: typeTable.length);
1190: typeTable = newTable;
1191: }
1192: typeTable[typeCount] = result;
1193: return result;
1194: }
1195:
1196: /**
1197: * Returns the index of the common super type of the two given types. This
1198: * method calls {@link #getCommonSuperClass} and caches the result in the
1199: * {@link #items} hash table to speedup future calls with the same
1200: * parameters.
1201: *
1202: * @param type1 index of an internal name in {@link #typeTable}.
1203: * @param type2 index of an internal name in {@link #typeTable}.
1204: * @return the index of the common super type of the two given types.
1205: */
1206: int getMergedType(final int type1, final int type2) {
1207: key2.type = TYPE_MERGED;
1208: key2.longVal = type1 | (((long) type2) << 32);
1209: key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2);
1210: Item result = get(key2);
1211: if (result == null) {
1212: String t = typeTable[type1].strVal1;
1213: String u = typeTable[type2].strVal1;
1214: key2.intVal = addType(getCommonSuperClass(t, u));
1215: result = new Item((short) 0, key2);
1216: put(result);
1217: }
1218: return result.intVal;
1219: }
1220:
1221: /**
1222: * Returns the common super type of the two given types. The default
1223: * implementation of this method <i>loads<i> the two given classes and uses
1224: * the java.lang.Class methods to find the common super class. It can be
1225: * overriden to compute this common super type in other ways, in particular
1226: * without actually loading any class, or to take into account the class
1227: * that is currently being generated by this ClassWriter, which can of
1228: * course not be loaded since it is under construction.
1229: *
1230: * @param type1 the internal name of a class.
1231: * @param type2 the internal name of another class.
1232: * @return the internal name of the common super class of the two given
1233: * classes.
1234: */
1235: protected String getCommonSuperClass(final String type1,
1236: final String type2) {
1237: Class c, d;
1238: try {
1239: c = Class.forName(type1.replace('/', '.'));
1240: d = Class.forName(type2.replace('/', '.'));
1241: } catch (ClassNotFoundException e) {
1242: throw new RuntimeException(e);
1243: }
1244: if (c.isAssignableFrom(d)) {
1245: return type1;
1246: }
1247: if (d.isAssignableFrom(c)) {
1248: return type2;
1249: }
1250: if (c.isInterface() || d.isInterface()) {
1251: return "java/lang/Object";
1252: } else {
1253: do {
1254: c = c.getSuperclass();
1255: } while (!c.isAssignableFrom(d));
1256: return c.getName().replace('.', '/');
1257: }
1258: }
1259:
1260: /**
1261: * Returns the constant pool's hash table item which is equal to the given
1262: * item.
1263: *
1264: * @param key a constant pool item.
1265: * @return the constant pool's hash table item which is equal to the given
1266: * item, or <tt>null</tt> if there is no such item.
1267: */
1268: private Item get(final Item key) {
1269: Item i = items[key.hashCode % items.length];
1270: while (i != null && !key.isEqualTo(i)) {
1271: i = i.next;
1272: }
1273: return i;
1274: }
1275:
1276: /**
1277: * Puts the given item in the constant pool's hash table. The hash table
1278: * <i>must</i> not already contains this item.
1279: *
1280: * @param i the item to be added to the constant pool's hash table.
1281: */
1282: private void put(final Item i) {
1283: if (index > threshold) {
1284: int ll = items.length;
1285: int nl = ll * 2 + 1;
1286: Item[] newItems = new Item[nl];
1287: for (int l = ll - 1; l >= 0; --l) {
1288: Item j = items[l];
1289: while (j != null) {
1290: int index = j.hashCode % newItems.length;
1291: Item k = j.next;
1292: j.next = newItems[index];
1293: newItems[index] = j;
1294: j = k;
1295: }
1296: }
1297: items = newItems;
1298: threshold = (int) (nl * 0.75);
1299: }
1300: int index = i.hashCode % items.length;
1301: i.next = items[index];
1302: items[index] = i;
1303: }
1304:
1305: /**
1306: * Puts one byte and two shorts into the constant pool.
1307: *
1308: * @param b a byte.
1309: * @param s1 a short.
1310: * @param s2 another short.
1311: */
1312: private void put122(final int b, final int s1, final int s2) {
1313: pool.put12(b, s1).putShort(s2);
1314: }
1315: }
|