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: */package com.tc.asm;
0030:
0031: import java.io.InputStream;
0032: import java.io.IOException;
0033:
0034: /**
0035: * A Java class parser to make a {@link ClassVisitor} visit an existing class.
0036: * This class parses a byte array conforming to the Java class file format and
0037: * calls the appropriate visit methods of a given class visitor for each field,
0038: * method and bytecode instruction encountered.
0039: *
0040: * @author Eric Bruneton
0041: * @author Eugene Kuleshov
0042: */
0043: public class ClassReader {
0044:
0045: /**
0046: * Flag to skip method code. If this class is set <code>CODE</code>
0047: * attribute won't be visited. This can be used, for example, to retrieve
0048: * annotations for methods and method parameters.
0049: */
0050: public final static int SKIP_CODE = 1;
0051:
0052: /**
0053: * Flag to skip the debug information in the class. If this flag is set the
0054: * debug information of the class is not visited, i.e. the
0055: * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
0056: * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be
0057: * called.
0058: */
0059: public final static int SKIP_DEBUG = 2;
0060:
0061: /**
0062: * Flag to skip the stack map frames in the class. If this flag is set the
0063: * stack map frames of the class is not visited, i.e. the
0064: * {@link MethodVisitor#visitFrame visitFrame} method will not be called.
0065: * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is
0066: * used: it avoids visiting frames that will be ignored and recomputed from
0067: * scratch in the class writer.
0068: */
0069: public final static int SKIP_FRAMES = 4;
0070:
0071: /**
0072: * Flag to expand the stack map frames. By default stack map frames are
0073: * visited in their original format (i.e. "expanded" for classes whose
0074: * version is less than V1_6, and "compressed" for the other classes). If
0075: * this flag is set, stack map frames are always visited in expanded format
0076: * (this option adds a decompression/recompression step in ClassReader and
0077: * ClassWriter which degrades performances quite a lot).
0078: */
0079: public final static int EXPAND_FRAMES = 8;
0080:
0081: /**
0082: * The class to be parsed. <i>The content of this array must not be
0083: * modified. This field is intended for {@link Attribute} sub classes, and
0084: * is normally not needed by class generators or adapters.</i>
0085: */
0086: public final byte[] b;
0087:
0088: /**
0089: * The start index of each constant pool item in {@link #b b}, plus one.
0090: * The one byte offset skips the constant pool item tag that indicates its
0091: * type.
0092: */
0093: private final int[] items;
0094:
0095: /**
0096: * The String objects corresponding to the CONSTANT_Utf8 items. This cache
0097: * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
0098: * which GREATLY improves performances (by a factor 2 to 3). This caching
0099: * strategy could be extended to all constant pool items, but its benefit
0100: * would not be so great for these items (because they are much less
0101: * expensive to parse than CONSTANT_Utf8 items).
0102: */
0103: private final String[] strings;
0104:
0105: /**
0106: * Maximum length of the strings contained in the constant pool of the
0107: * class.
0108: */
0109: private final int maxStringLength;
0110:
0111: /**
0112: * Start index of the class header information (access, name...) in
0113: * {@link #b b}.
0114: */
0115: public final int header;
0116:
0117: // ------------------------------------------------------------------------
0118: // Constructors
0119: // ------------------------------------------------------------------------
0120:
0121: /**
0122: * Constructs a new {@link ClassReader} object.
0123: *
0124: * @param b the bytecode of the class to be read.
0125: */
0126: public ClassReader(final byte[] b) {
0127: this (b, 0, b.length);
0128: }
0129:
0130: /**
0131: * Constructs a new {@link ClassReader} object.
0132: *
0133: * @param b the bytecode of the class to be read.
0134: * @param off the start offset of the class data.
0135: * @param len the length of the class data.
0136: */
0137: public ClassReader(final byte[] b, final int off, final int len) {
0138: this .b = b;
0139: // parses the constant pool
0140: items = new int[readUnsignedShort(off + 8)];
0141: int n = items.length;
0142: strings = new String[n];
0143: int max = 0;
0144: int index = off + 10;
0145: for (int i = 1; i < n; ++i) {
0146: items[i] = index + 1;
0147: int size;
0148: switch (b[index]) {
0149: case ClassWriter.FIELD:
0150: case ClassWriter.METH:
0151: case ClassWriter.IMETH:
0152: case ClassWriter.INT:
0153: case ClassWriter.FLOAT:
0154: case ClassWriter.NAME_TYPE:
0155: size = 5;
0156: break;
0157: case ClassWriter.LONG:
0158: case ClassWriter.DOUBLE:
0159: size = 9;
0160: ++i;
0161: break;
0162: case ClassWriter.UTF8:
0163: size = 3 + readUnsignedShort(index + 1);
0164: if (size > max) {
0165: max = size;
0166: }
0167: break;
0168: // case ClassWriter.CLASS:
0169: // case ClassWriter.STR:
0170: default:
0171: size = 3;
0172: break;
0173: }
0174: index += size;
0175: }
0176: maxStringLength = max;
0177: // the class header information starts just after the constant pool
0178: header = index;
0179: }
0180:
0181: /**
0182: * Returns the class's access flags (see {@link Opcodes}). This value may
0183: * not reflect Deprecated and Synthetic flags when bytecode is before 1.5
0184: * and those flags are represented by attributes.
0185: *
0186: * @return the class access flags
0187: *
0188: * @see ClassVisitor#visit(int, int, String, String, String, String[])
0189: */
0190: public int getAccess() {
0191: return readUnsignedShort(header);
0192: }
0193:
0194: /**
0195: * Returns the internal name of the class (see
0196: * {@link Type#getInternalName() getInternalName}).
0197: *
0198: * @return the internal class name
0199: *
0200: * @see ClassVisitor#visit(int, int, String, String, String, String[])
0201: */
0202: public String getClassName() {
0203: return readClass(header + 2, new char[maxStringLength]);
0204: }
0205:
0206: /**
0207: * Returns the internal of name of the super class (see
0208: * {@link Type#getInternalName() getInternalName}). For interfaces, the
0209: * super class is {@link Object}.
0210: *
0211: * @return the internal name of super class, or <tt>null</tt> for
0212: * {@link Object} class.
0213: *
0214: * @see ClassVisitor#visit(int, int, String, String, String, String[])
0215: */
0216: public String getSuperName() {
0217: int n = items[readUnsignedShort(header + 4)];
0218: return n == 0 ? null : readUTF8(n, new char[maxStringLength]);
0219: }
0220:
0221: /**
0222: * Returns the internal names of the class's interfaces (see
0223: * {@link Type#getInternalName() getInternalName}).
0224: *
0225: * @return the array of internal names for all implemented interfaces or
0226: * <tt>null</tt>.
0227: *
0228: * @see ClassVisitor#visit(int, int, String, String, String, String[])
0229: */
0230: public String[] getInterfaces() {
0231: int index = header + 6;
0232: int n = readUnsignedShort(index);
0233: String[] interfaces = new String[n];
0234: if (n > 0) {
0235: char[] buf = new char[maxStringLength];
0236: for (int i = 0; i < n; ++i) {
0237: index += 2;
0238: interfaces[i] = readClass(index, buf);
0239: }
0240: }
0241: return interfaces;
0242: }
0243:
0244: /**
0245: * Copies the constant pool data into the given {@link ClassWriter}. Should
0246: * be called before the {@link #accept(ClassVisitor,int)} method.
0247: *
0248: * @param classWriter the {@link ClassWriter} to copy constant pool into.
0249: */
0250: void copyPool(final ClassWriter classWriter) {
0251: char[] buf = new char[maxStringLength];
0252: int ll = items.length;
0253: Item[] items2 = new Item[ll];
0254: for (int i = 1; i < ll; i++) {
0255: int index = items[i];
0256: int tag = b[index - 1];
0257: Item item = new Item(i);
0258: int nameType;
0259: switch (tag) {
0260: case ClassWriter.FIELD:
0261: case ClassWriter.METH:
0262: case ClassWriter.IMETH:
0263: nameType = items[readUnsignedShort(index + 2)];
0264: item.set(tag, readClass(index, buf), readUTF8(nameType,
0265: buf), readUTF8(nameType + 2, buf));
0266: break;
0267:
0268: case ClassWriter.INT:
0269: item.set(readInt(index));
0270: break;
0271:
0272: case ClassWriter.FLOAT:
0273: item.set(Float.intBitsToFloat(readInt(index)));
0274: break;
0275:
0276: case ClassWriter.NAME_TYPE:
0277: item.set(tag, readUTF8(index, buf), readUTF8(index + 2,
0278: buf), null);
0279: break;
0280:
0281: case ClassWriter.LONG:
0282: item.set(readLong(index));
0283: ++i;
0284: break;
0285:
0286: case ClassWriter.DOUBLE:
0287: item.set(Double.longBitsToDouble(readLong(index)));
0288: ++i;
0289: break;
0290:
0291: case ClassWriter.UTF8: {
0292: String s = strings[i];
0293: if (s == null) {
0294: index = items[i];
0295: s = strings[i] = readUTF(index + 2,
0296: readUnsignedShort(index), buf);
0297: }
0298: item.set(tag, s, null, null);
0299: }
0300: break;
0301:
0302: // case ClassWriter.STR:
0303: // case ClassWriter.CLASS:
0304: default:
0305: item.set(tag, readUTF8(index, buf), null, null);
0306: break;
0307: }
0308:
0309: int index2 = item.hashCode % items2.length;
0310: item.next = items2[index2];
0311: items2[index2] = item;
0312: }
0313:
0314: int off = items[1] - 1;
0315: classWriter.pool.putByteArray(b, off, header - off);
0316: classWriter.items = items2;
0317: classWriter.threshold = (int) (0.75d * ll);
0318: classWriter.index = ll;
0319: }
0320:
0321: /**
0322: * Constructs a new {@link ClassReader} object.
0323: *
0324: * @param is an input stream from which to read the class.
0325: * @throws IOException if a problem occurs during reading.
0326: */
0327: public ClassReader(final InputStream is) throws IOException {
0328: this (readClass(is));
0329: }
0330:
0331: /**
0332: * Constructs a new {@link ClassReader} object.
0333: *
0334: * @param name the fully qualified name of the class to be read.
0335: * @throws IOException if an exception occurs during reading.
0336: */
0337: public ClassReader(final String name) throws IOException {
0338: this (ClassLoader.getSystemResourceAsStream(name.replace('.',
0339: '/')
0340: + ".class"));
0341: }
0342:
0343: /**
0344: * Reads the bytecode of a class.
0345: *
0346: * @param is an input stream from which to read the class.
0347: * @return the bytecode read from the given input stream.
0348: * @throws IOException if a problem occurs during reading.
0349: */
0350: private static byte[] readClass(final InputStream is)
0351: throws IOException {
0352: if (is == null) {
0353: throw new IOException("Class not found");
0354: }
0355: byte[] b = new byte[is.available()];
0356: int len = 0;
0357: while (true) {
0358: int n = is.read(b, len, b.length - len);
0359: if (n == -1) {
0360: if (len < b.length) {
0361: byte[] c = new byte[len];
0362: System.arraycopy(b, 0, c, 0, len);
0363: b = c;
0364: }
0365: return b;
0366: }
0367: len += n;
0368: if (len == b.length) {
0369: byte[] c = new byte[b.length + 1000];
0370: System.arraycopy(b, 0, c, 0, len);
0371: b = c;
0372: }
0373: }
0374: }
0375:
0376: // ------------------------------------------------------------------------
0377: // Public methods
0378: // ------------------------------------------------------------------------
0379:
0380: /**
0381: * Makes the given visitor visit the Java class of this {@link ClassReader}.
0382: * This class is the one specified in the constructor (see
0383: * {@link #ClassReader(byte[]) ClassReader}).
0384: *
0385: * @param classVisitor the visitor that must visit this class.
0386: * @param flags option flags that can be used to modify the default behavior
0387: * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}.
0388: */
0389: public void accept(final ClassVisitor classVisitor, final int flags) {
0390: accept(classVisitor, new Attribute[0], flags);
0391: }
0392:
0393: /**
0394: * Makes the given visitor visit the Java class of this {@link ClassReader}.
0395: * This class is the one specified in the constructor (see
0396: * {@link #ClassReader(byte[]) ClassReader}).
0397: *
0398: * @param classVisitor the visitor that must visit this class.
0399: * @param attrs prototypes of the attributes that must be parsed during the
0400: * visit of the class. Any attribute whose type is not equal to the
0401: * type of one the prototypes will not be parsed: its byte array
0402: * value will be passed unchanged to the ClassWriter. <i>This may
0403: * corrupt it if this value contains references to the constant pool,
0404: * or has syntactic or semantic links with a class element that has
0405: * been transformed by a class adapter between the reader and the
0406: * writer</i>.
0407: * @param flags option flags that can be used to modify the default behavior
0408: * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}.
0409: */
0410: public void accept(final ClassVisitor classVisitor,
0411: final Attribute[] attrs, final int flags) {
0412: byte[] b = this .b; // the bytecode array
0413: char[] c = new char[maxStringLength]; // buffer used to read strings
0414: int i, j, k; // loop variables
0415: int u, v, w; // indexes in b
0416: Attribute attr;
0417:
0418: int access;
0419: String name;
0420: String desc;
0421: String attrName;
0422: String signature;
0423: int anns = 0;
0424: int ianns = 0;
0425: Attribute cattrs = null;
0426:
0427: // visits the header
0428: u = header;
0429: access = readUnsignedShort(u);
0430: name = readClass(u + 2, c);
0431: v = items[readUnsignedShort(u + 4)];
0432: String super ClassName = v == 0 ? null : readUTF8(v, c);
0433: String[] implementedItfs = new String[readUnsignedShort(u + 6)];
0434: w = 0;
0435: u += 8;
0436: for (i = 0; i < implementedItfs.length; ++i) {
0437: implementedItfs[i] = readClass(u, c);
0438: u += 2;
0439: }
0440:
0441: boolean skipCode = (flags & SKIP_CODE) != 0;
0442: boolean skipDebug = (flags & SKIP_DEBUG) != 0;
0443: boolean unzip = (flags & EXPAND_FRAMES) != 0;
0444:
0445: // skips fields and methods
0446: v = u;
0447: i = readUnsignedShort(v);
0448: v += 2;
0449: for (; i > 0; --i) {
0450: j = readUnsignedShort(v + 6);
0451: v += 8;
0452: for (; j > 0; --j) {
0453: v += 6 + readInt(v + 2);
0454: }
0455: }
0456: i = readUnsignedShort(v);
0457: v += 2;
0458: for (; i > 0; --i) {
0459: j = readUnsignedShort(v + 6);
0460: v += 8;
0461: for (; j > 0; --j) {
0462: v += 6 + readInt(v + 2);
0463: }
0464: }
0465: // reads the class's attributes
0466: signature = null;
0467: String sourceFile = null;
0468: String sourceDebug = null;
0469: String enclosingOwner = null;
0470: String enclosingName = null;
0471: String enclosingDesc = null;
0472:
0473: i = readUnsignedShort(v);
0474: v += 2;
0475: for (; i > 0; --i) {
0476: attrName = readUTF8(v, c);
0477: // tests are sorted in decreasing frequency order
0478: // (based on frequencies observed on typical classes)
0479: if (attrName.equals("SourceFile")) {
0480: sourceFile = readUTF8(v + 6, c);
0481: } else if (attrName.equals("InnerClasses")) {
0482: w = v + 6;
0483: } else if (attrName.equals("EnclosingMethod")) {
0484: enclosingOwner = readClass(v + 6, c);
0485: int item = readUnsignedShort(v + 8);
0486: if (item != 0) {
0487: enclosingName = readUTF8(items[item], c);
0488: enclosingDesc = readUTF8(items[item] + 2, c);
0489: }
0490: } else if (attrName.equals("Signature")) {
0491: signature = readUTF8(v + 6, c);
0492: } else if (attrName.equals("RuntimeVisibleAnnotations")) {
0493: anns = v + 6;
0494: } else if (attrName.equals("Deprecated")) {
0495: access |= Opcodes.ACC_DEPRECATED;
0496: } else if (attrName.equals("Synthetic")) {
0497: access |= Opcodes.ACC_SYNTHETIC;
0498: } else if (attrName.equals("SourceDebugExtension")) {
0499: int len = readInt(v + 2);
0500: sourceDebug = readUTF(v + 6, len, new char[len]);
0501: } else if (attrName.equals("RuntimeInvisibleAnnotations")) {
0502: ianns = v + 6;
0503: } else {
0504: attr = readAttribute(attrs, attrName, v + 6,
0505: readInt(v + 2), c, -1, null);
0506: if (attr != null) {
0507: attr.next = cattrs;
0508: cattrs = attr;
0509: }
0510: }
0511: v += 6 + readInt(v + 2);
0512: }
0513: // calls the visit method
0514: classVisitor.visit(readInt(4), access, name, signature,
0515: super ClassName, implementedItfs);
0516:
0517: // calls the visitSource method
0518: if (!skipDebug && (sourceFile != null || sourceDebug != null)) {
0519: classVisitor.visitSource(sourceFile, sourceDebug);
0520: }
0521:
0522: // calls the visitOuterClass method
0523: if (enclosingOwner != null) {
0524: classVisitor.visitOuterClass(enclosingOwner, enclosingName,
0525: enclosingDesc);
0526: }
0527:
0528: // visits the class annotations
0529: for (i = 1; i >= 0; --i) {
0530: v = i == 0 ? ianns : anns;
0531: if (v != 0) {
0532: j = readUnsignedShort(v);
0533: v += 2;
0534: for (; j > 0; --j) {
0535: v = readAnnotationValues(v + 2, c, true,
0536: classVisitor.visitAnnotation(
0537: readUTF8(v, c), i != 0));
0538: }
0539: }
0540: }
0541:
0542: // visits the class attributes
0543: while (cattrs != null) {
0544: attr = cattrs.next;
0545: cattrs.next = null;
0546: classVisitor.visitAttribute(cattrs);
0547: cattrs = attr;
0548: }
0549:
0550: // calls the visitInnerClass method
0551: if (w != 0) {
0552: i = readUnsignedShort(w);
0553: w += 2;
0554: for (; i > 0; --i) {
0555: classVisitor.visitInnerClass(
0556: readUnsignedShort(w) == 0 ? null : readClass(w,
0557: c),
0558: readUnsignedShort(w + 2) == 0 ? null
0559: : readClass(w + 2, c),
0560: readUnsignedShort(w + 4) == 0 ? null
0561: : readUTF8(w + 4, c),
0562: readUnsignedShort(w + 6));
0563: w += 8;
0564: }
0565: }
0566:
0567: // visits the fields
0568: i = readUnsignedShort(u);
0569: u += 2;
0570: for (; i > 0; --i) {
0571: access = readUnsignedShort(u);
0572: name = readUTF8(u + 2, c);
0573: desc = readUTF8(u + 4, c);
0574: // visits the field's attributes and looks for a ConstantValue
0575: // attribute
0576: int fieldValueItem = 0;
0577: signature = null;
0578: anns = 0;
0579: ianns = 0;
0580: cattrs = null;
0581:
0582: j = readUnsignedShort(u + 6);
0583: u += 8;
0584: for (; j > 0; --j) {
0585: attrName = readUTF8(u, c);
0586: // tests are sorted in decreasing frequency order
0587: // (based on frequencies observed on typical classes)
0588: if (attrName.equals("ConstantValue")) {
0589: fieldValueItem = readUnsignedShort(u + 6);
0590: } else if (attrName.equals("Signature")) {
0591: signature = readUTF8(u + 6, c);
0592: } else if (attrName.equals("Deprecated")) {
0593: access |= Opcodes.ACC_DEPRECATED;
0594: } else if (attrName.equals("Synthetic")) {
0595: access |= Opcodes.ACC_SYNTHETIC;
0596: } else if (attrName.equals("RuntimeVisibleAnnotations")) {
0597: anns = u + 6;
0598: } else if (attrName
0599: .equals("RuntimeInvisibleAnnotations")) {
0600: ianns = u + 6;
0601: } else {
0602: attr = readAttribute(attrs, attrName, u + 6,
0603: readInt(u + 2), c, -1, null);
0604: if (attr != null) {
0605: attr.next = cattrs;
0606: cattrs = attr;
0607: }
0608: }
0609: u += 6 + readInt(u + 2);
0610: }
0611: // visits the field
0612: FieldVisitor fv = classVisitor.visitField(access, name,
0613: desc, signature, fieldValueItem == 0 ? null
0614: : readConst(fieldValueItem, c));
0615: // visits the field annotations and attributes
0616: if (fv != null) {
0617: for (j = 1; j >= 0; --j) {
0618: v = j == 0 ? ianns : anns;
0619: if (v != 0) {
0620: k = readUnsignedShort(v);
0621: v += 2;
0622: for (; k > 0; --k) {
0623: v = readAnnotationValues(v + 2, c, true, fv
0624: .visitAnnotation(readUTF8(v, c),
0625: j != 0));
0626: }
0627: }
0628: }
0629: while (cattrs != null) {
0630: attr = cattrs.next;
0631: cattrs.next = null;
0632: fv.visitAttribute(cattrs);
0633: cattrs = attr;
0634: }
0635: fv.visitEnd();
0636: }
0637: }
0638:
0639: // visits the methods
0640: i = readUnsignedShort(u);
0641: u += 2;
0642: for (; i > 0; --i) {
0643: int u0 = u + 6;
0644: access = readUnsignedShort(u);
0645: name = readUTF8(u + 2, c);
0646: desc = readUTF8(u + 4, c);
0647: signature = null;
0648: anns = 0;
0649: ianns = 0;
0650: int dann = 0;
0651: int mpanns = 0;
0652: int impanns = 0;
0653: cattrs = null;
0654: v = 0;
0655: w = 0;
0656:
0657: // looks for Code and Exceptions attributes
0658: j = readUnsignedShort(u + 6);
0659: u += 8;
0660: for (; j > 0; --j) {
0661: attrName = readUTF8(u, c);
0662: int attrSize = readInt(u + 2);
0663: u += 6;
0664: // tests are sorted in decreasing frequency order
0665: // (based on frequencies observed on typical classes)
0666: if (attrName.equals("Code")) {
0667: if (!skipCode) {
0668: v = u;
0669: }
0670: } else if (attrName.equals("Exceptions")) {
0671: w = u;
0672: } else if (attrName.equals("Signature")) {
0673: signature = readUTF8(u, c);
0674: } else if (attrName.equals("Deprecated")) {
0675: access |= Opcodes.ACC_DEPRECATED;
0676: } else if (attrName.equals("RuntimeVisibleAnnotations")) {
0677: anns = u;
0678: } else if (attrName.equals("AnnotationDefault")) {
0679: dann = u;
0680: } else if (attrName.equals("Synthetic")) {
0681: access |= Opcodes.ACC_SYNTHETIC;
0682: } else if (attrName
0683: .equals("RuntimeInvisibleAnnotations")) {
0684: ianns = u;
0685: } else if (attrName
0686: .equals("RuntimeVisibleParameterAnnotations")) {
0687: mpanns = u;
0688: } else if (attrName
0689: .equals("RuntimeInvisibleParameterAnnotations")) {
0690: impanns = u;
0691: } else {
0692: attr = readAttribute(attrs, attrName, u, attrSize,
0693: c, -1, null);
0694: if (attr != null) {
0695: attr.next = cattrs;
0696: cattrs = attr;
0697: }
0698: }
0699: u += attrSize;
0700: }
0701: // reads declared exceptions
0702: String[] exceptions;
0703: if (w == 0) {
0704: exceptions = null;
0705: } else {
0706: exceptions = new String[readUnsignedShort(w)];
0707: w += 2;
0708: for (j = 0; j < exceptions.length; ++j) {
0709: exceptions[j] = readClass(w, c);
0710: w += 2;
0711: }
0712: }
0713:
0714: // visits the method's code, if any
0715: MethodVisitor mv = classVisitor.visitMethod(access, name,
0716: desc, signature, exceptions);
0717:
0718: if (mv != null) {
0719: /*
0720: * if the returned MethodVisitor is in fact a MethodWriter, it
0721: * means there is no method adapter between the reader and the
0722: * writer. If, in addition, the writer's constant pool was
0723: * copied from this reader (mw.cw.cr == this), and the signature
0724: * and exceptions of the method have not been changed, then it
0725: * is possible to skip all visit events and just copy the
0726: * original code of the method to the writer (the access, name
0727: * and descriptor can have been changed, this is not important
0728: * since they are not copied as is from the reader).
0729: */
0730: if (mv instanceof MethodWriter) {
0731: MethodWriter mw = (MethodWriter) mv;
0732: if (mw.cw.cr == this ) {
0733: if (signature == mw.signature) {
0734: boolean sameExceptions = false;
0735: if (exceptions == null) {
0736: sameExceptions = mw.exceptionCount == 0;
0737: } else {
0738: if (exceptions.length == mw.exceptionCount) {
0739: sameExceptions = true;
0740: for (j = exceptions.length - 1; j >= 0; --j) {
0741: w -= 2;
0742: if (mw.exceptions[j] != readUnsignedShort(w)) {
0743: sameExceptions = false;
0744: break;
0745: }
0746: }
0747: }
0748: }
0749: if (sameExceptions) {
0750: /*
0751: * we do not copy directly the code into
0752: * MethodWriter to save a byte array copy
0753: * operation. The real copy will be done in
0754: * ClassWriter.toByteArray().
0755: */
0756: mw.classReaderOffset = u0;
0757: mw.classReaderLength = u - u0;
0758: continue;
0759: }
0760: }
0761: }
0762: }
0763:
0764: if (dann != 0) {
0765: AnnotationVisitor dv = mv.visitAnnotationDefault();
0766: readAnnotationValue(dann, c, null, dv);
0767: if (dv != null) {
0768: dv.visitEnd();
0769: }
0770: }
0771: for (j = 1; j >= 0; --j) {
0772: w = j == 0 ? ianns : anns;
0773: if (w != 0) {
0774: k = readUnsignedShort(w);
0775: w += 2;
0776: for (; k > 0; --k) {
0777: w = readAnnotationValues(w + 2, c, true, mv
0778: .visitAnnotation(readUTF8(w, c),
0779: j != 0));
0780: }
0781: }
0782: }
0783: if (mpanns != 0) {
0784: readParameterAnnotations(mpanns, c, true, mv);
0785: }
0786: if (impanns != 0) {
0787: readParameterAnnotations(impanns, c, false, mv);
0788: }
0789: while (cattrs != null) {
0790: attr = cattrs.next;
0791: cattrs.next = null;
0792: mv.visitAttribute(cattrs);
0793: cattrs = attr;
0794: }
0795: }
0796:
0797: if (mv != null && v != 0) {
0798: int maxStack = readUnsignedShort(v);
0799: int maxLocals = readUnsignedShort(v + 2);
0800: int codeLength = readInt(v + 4);
0801: v += 8;
0802:
0803: int codeStart = v;
0804: int codeEnd = v + codeLength;
0805:
0806: mv.visitCode();
0807:
0808: // 1st phase: finds the labels
0809: int label;
0810: Label[] labels = new Label[codeLength + 1];
0811: while (v < codeEnd) {
0812: int opcode = b[v] & 0xFF;
0813: switch (ClassWriter.TYPE[opcode]) {
0814: case ClassWriter.NOARG_INSN:
0815: case ClassWriter.IMPLVAR_INSN:
0816: v += 1;
0817: break;
0818: case ClassWriter.LABEL_INSN:
0819: label = v - codeStart + readShort(v + 1);
0820: if (labels[label] == null) {
0821: labels[label] = new Label();
0822: }
0823: v += 3;
0824: break;
0825: case ClassWriter.LABELW_INSN:
0826: label = v - codeStart + readInt(v + 1);
0827: if (labels[label] == null) {
0828: labels[label] = new Label();
0829: }
0830: v += 5;
0831: break;
0832: case ClassWriter.WIDE_INSN:
0833: opcode = b[v + 1] & 0xFF;
0834: if (opcode == Opcodes.IINC) {
0835: v += 6;
0836: } else {
0837: v += 4;
0838: }
0839: break;
0840: case ClassWriter.TABL_INSN:
0841: // skips 0 to 3 padding bytes
0842: w = v - codeStart;
0843: v = v + 4 - (w & 3);
0844: // reads instruction
0845: label = w + readInt(v);
0846: if (labels[label] == null) {
0847: labels[label] = new Label();
0848: }
0849: j = readInt(v + 8) - readInt(v + 4) + 1;
0850: v += 12;
0851: for (; j > 0; --j) {
0852: label = w + readInt(v);
0853: v += 4;
0854: if (labels[label] == null) {
0855: labels[label] = new Label();
0856: }
0857: }
0858: break;
0859: case ClassWriter.LOOK_INSN:
0860: // skips 0 to 3 padding bytes
0861: w = v - codeStart;
0862: v = v + 4 - (w & 3);
0863: // reads instruction
0864: label = w + readInt(v);
0865: if (labels[label] == null) {
0866: labels[label] = new Label();
0867: }
0868: j = readInt(v + 4);
0869: v += 8;
0870: for (; j > 0; --j) {
0871: label = w + readInt(v + 4);
0872: v += 8;
0873: if (labels[label] == null) {
0874: labels[label] = new Label();
0875: }
0876: }
0877: break;
0878: case ClassWriter.VAR_INSN:
0879: case ClassWriter.SBYTE_INSN:
0880: case ClassWriter.LDC_INSN:
0881: v += 2;
0882: break;
0883: case ClassWriter.SHORT_INSN:
0884: case ClassWriter.LDCW_INSN:
0885: case ClassWriter.FIELDORMETH_INSN:
0886: case ClassWriter.TYPE_INSN:
0887: case ClassWriter.IINC_INSN:
0888: v += 3;
0889: break;
0890: case ClassWriter.ITFMETH_INSN:
0891: v += 5;
0892: break;
0893: // case MANA_INSN:
0894: default:
0895: v += 4;
0896: break;
0897: }
0898: }
0899: // parses the try catch entries
0900: j = readUnsignedShort(v);
0901: v += 2;
0902: for (; j > 0; --j) {
0903: label = readUnsignedShort(v);
0904: Label start = labels[label];
0905: if (start == null) {
0906: labels[label] = start = new Label();
0907: }
0908: label = readUnsignedShort(v + 2);
0909: Label end = labels[label];
0910: if (end == null) {
0911: labels[label] = end = new Label();
0912: }
0913: label = readUnsignedShort(v + 4);
0914: Label handler = labels[label];
0915: if (handler == null) {
0916: labels[label] = handler = new Label();
0917: }
0918: int type = readUnsignedShort(v + 6);
0919: if (type == 0) {
0920: mv
0921: .visitTryCatchBlock(start, end,
0922: handler, null);
0923: } else {
0924: mv.visitTryCatchBlock(start, end, handler,
0925: readUTF8(items[type], c));
0926: }
0927: v += 8;
0928: }
0929: // parses the local variable, line number tables, and code
0930: // attributes
0931: int varTable = 0;
0932: int varTypeTable = 0;
0933: int stackMap = 0;
0934: int frameCount = 0;
0935: int frameMode = 0;
0936: int frameOffset = 0;
0937: int frameLocalCount = 0;
0938: int frameLocalDiff = 0;
0939: int frameStackCount = 0;
0940: Object[] frameLocal = null;
0941: Object[] frameStack = null;
0942: boolean zip = true;
0943: cattrs = null;
0944: j = readUnsignedShort(v);
0945: v += 2;
0946: for (; j > 0; --j) {
0947: attrName = readUTF8(v, c);
0948: if (attrName.equals("LocalVariableTable")) {
0949: if (!skipDebug) {
0950: varTable = v + 6;
0951: k = readUnsignedShort(v + 6);
0952: w = v + 8;
0953: for (; k > 0; --k) {
0954: label = readUnsignedShort(w);
0955: if (labels[label] == null) {
0956: labels[label] = new Label(true);
0957: }
0958: label += readUnsignedShort(w + 2);
0959: if (labels[label] == null) {
0960: labels[label] = new Label(true);
0961: }
0962: w += 10;
0963: }
0964: }
0965: } else if (attrName
0966: .equals("LocalVariableTypeTable")) {
0967: varTypeTable = v + 6;
0968: } else if (attrName.equals("LineNumberTable")) {
0969: if (!skipDebug) {
0970: k = readUnsignedShort(v + 6);
0971: w = v + 8;
0972: for (; k > 0; --k) {
0973: label = readUnsignedShort(w);
0974: if (labels[label] == null) {
0975: labels[label] = new Label(true);
0976: }
0977: labels[label].line = readUnsignedShort(w + 2);
0978: w += 4;
0979: }
0980: }
0981: } else if (attrName.equals("StackMapTable")) {
0982: if ((flags & SKIP_FRAMES) == 0) {
0983: stackMap = v + 8;
0984: frameCount = readUnsignedShort(v + 6);
0985: }
0986: /*
0987: * here we do not extract the labels corresponding to
0988: * the attribute content. This would require a full
0989: * parsing of the attribute, which would need to be
0990: * repeated in the second phase (see below). Instead the
0991: * content of the attribute is read one frame at a time
0992: * (i.e. after a frame has been visited, the next frame
0993: * is read), and the labels it contains are also
0994: * extracted one frame at a time. Thanks to the ordering
0995: * of frames, having only a "one frame lookahead" is not
0996: * a problem, i.e. it is not possible to see an offset
0997: * smaller than the offset of the current insn and for
0998: * which no Label exist.
0999: */
1000: // TODO true for frame offsets,
1001: // but for UNINITIALIZED type offsets?
1002: } else if (attrName.equals("StackMap")) {
1003: if ((flags & SKIP_FRAMES) == 0) {
1004: stackMap = v + 8;
1005: frameCount = readUnsignedShort(v + 6);
1006: zip = false;
1007: }
1008: /*
1009: * IMPORTANT! here we assume that the frames are
1010: * ordered, as in the StackMapTable attribute, although
1011: * this is not guaranteed by the attribute format.
1012: */
1013: } else {
1014: for (k = 0; k < attrs.length; ++k) {
1015: if (attrs[k].type.equals(attrName)) {
1016: attr = attrs[k].read(this , v + 6,
1017: readInt(v + 2), c,
1018: codeStart - 8, labels);
1019: if (attr != null) {
1020: attr.next = cattrs;
1021: cattrs = attr;
1022: }
1023: }
1024: }
1025: }
1026: v += 6 + readInt(v + 2);
1027: }
1028:
1029: // 2nd phase: visits each instruction
1030: if (stackMap != 0) {
1031: // creates the very first (implicit) frame from the method
1032: // descriptor
1033: frameLocal = new Object[maxLocals];
1034: frameStack = new Object[maxStack];
1035: if (unzip) {
1036: int local = 0;
1037: if ((access & Opcodes.ACC_STATIC) == 0) {
1038: if (name.equals("<init>")) {
1039: frameLocal[local++] = Opcodes.UNINITIALIZED_THIS;
1040: } else {
1041: frameLocal[local++] = readClass(
1042: header + 2, c);
1043: }
1044: }
1045: j = 1;
1046: loop: while (true) {
1047: k = j;
1048: switch (desc.charAt(j++)) {
1049: case 'Z':
1050: case 'C':
1051: case 'B':
1052: case 'S':
1053: case 'I':
1054: frameLocal[local++] = Opcodes.INTEGER;
1055: break;
1056: case 'F':
1057: frameLocal[local++] = Opcodes.FLOAT;
1058: break;
1059: case 'J':
1060: frameLocal[local++] = Opcodes.LONG;
1061: break;
1062: case 'D':
1063: frameLocal[local++] = Opcodes.DOUBLE;
1064: break;
1065: case '[':
1066: while (desc.charAt(j) == '[') {
1067: ++j;
1068: }
1069: if (desc.charAt(j) == 'L') {
1070: ++j;
1071: while (desc.charAt(j) != ';') {
1072: ++j;
1073: }
1074: }
1075: frameLocal[local++] = desc.substring(k,
1076: ++j);
1077: break;
1078: case 'L':
1079: while (desc.charAt(j) != ';') {
1080: ++j;
1081: }
1082: frameLocal[local++] = desc.substring(
1083: k + 1, j++);
1084: break;
1085: default:
1086: break loop;
1087: }
1088: }
1089: frameLocalCount = local;
1090: }
1091: /*
1092: * for the first explicit frame the offset is not
1093: * offset_delta + 1 but only offset_delta; setting the
1094: * implicit frame offset to -1 allow the use of the
1095: * "offset_delta + 1" rule in all cases
1096: */
1097: frameOffset = -1;
1098: }
1099: v = codeStart;
1100: Label l;
1101: while (v < codeEnd) {
1102: w = v - codeStart;
1103:
1104: l = labels[w];
1105: if (l != null) {
1106: mv.visitLabel(l);
1107: if (!skipDebug && l.line > 0) {
1108: mv.visitLineNumber(l.line, l);
1109: }
1110: }
1111:
1112: while (frameLocal != null
1113: && (frameOffset == w || frameOffset == -1)) {
1114: // if there is a frame for this offset,
1115: // makes the visitor visit it,
1116: // and reads the next frame if there is one.
1117: if (!zip || unzip) {
1118: mv.visitFrame(Opcodes.F_NEW,
1119: frameLocalCount, frameLocal,
1120: frameStackCount, frameStack);
1121: } else if (frameOffset != -1) {
1122: mv.visitFrame(frameMode, frameLocalDiff,
1123: frameLocal, frameStackCount,
1124: frameStack);
1125: }
1126:
1127: if (frameCount > 0) {
1128: int tag, delta, n;
1129: if (zip) {
1130: tag = b[stackMap++] & 0xFF;
1131: } else {
1132: tag = MethodWriter.FULL_FRAME;
1133: frameOffset = -1;
1134: }
1135: frameLocalDiff = 0;
1136: if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) {
1137: delta = tag;
1138: frameMode = Opcodes.F_SAME;
1139: frameStackCount = 0;
1140: } else if (tag < MethodWriter.RESERVED) {
1141: delta = tag
1142: - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;
1143: stackMap = readFrameType(frameStack, 0,
1144: stackMap, c, labels);
1145: frameMode = Opcodes.F_SAME1;
1146: frameStackCount = 1;
1147: } else {
1148: delta = readUnsignedShort(stackMap);
1149: stackMap += 2;
1150: if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
1151: stackMap = readFrameType(
1152: frameStack, 0, stackMap, c,
1153: labels);
1154: frameMode = Opcodes.F_SAME1;
1155: frameStackCount = 1;
1156: } else if (tag >= MethodWriter.CHOP_FRAME
1157: && tag < MethodWriter.SAME_FRAME_EXTENDED) {
1158: frameMode = Opcodes.F_CHOP;
1159: frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED
1160: - tag;
1161: frameLocalCount -= frameLocalDiff;
1162: frameStackCount = 0;
1163: } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) {
1164: frameMode = Opcodes.F_SAME;
1165: frameStackCount = 0;
1166: } else if (tag < MethodWriter.FULL_FRAME) {
1167: j = unzip ? frameLocalCount : 0;
1168: for (k = tag
1169: - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--) {
1170: stackMap = readFrameType(
1171: frameLocal, j++,
1172: stackMap, c, labels);
1173: }
1174: frameMode = Opcodes.F_APPEND;
1175: frameLocalDiff = tag
1176: - MethodWriter.SAME_FRAME_EXTENDED;
1177: frameLocalCount += frameLocalDiff;
1178: frameStackCount = 0;
1179: } else { // if (tag == FULL_FRAME) {
1180: frameMode = Opcodes.F_FULL;
1181: n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap);
1182: stackMap += 2;
1183: for (j = 0; n > 0; n--) {
1184: stackMap = readFrameType(
1185: frameLocal, j++,
1186: stackMap, c, labels);
1187: }
1188: n = frameStackCount = readUnsignedShort(stackMap);
1189: stackMap += 2;
1190: for (j = 0; n > 0; n--) {
1191: stackMap = readFrameType(
1192: frameStack, j++,
1193: stackMap, c, labels);
1194: }
1195: }
1196: }
1197: frameOffset += delta + 1;
1198: if (labels[frameOffset] == null) {
1199: labels[frameOffset] = new Label();
1200: }
1201:
1202: --frameCount;
1203: } else {
1204: frameLocal = null;
1205: }
1206: }
1207:
1208: int opcode = b[v] & 0xFF;
1209: switch (ClassWriter.TYPE[opcode]) {
1210: case ClassWriter.NOARG_INSN:
1211: mv.visitInsn(opcode);
1212: v += 1;
1213: break;
1214: case ClassWriter.IMPLVAR_INSN:
1215: if (opcode > Opcodes.ISTORE) {
1216: opcode -= 59; // ISTORE_0
1217: mv.visitVarInsn(Opcodes.ISTORE
1218: + (opcode >> 2), opcode & 0x3);
1219: } else {
1220: opcode -= 26; // ILOAD_0
1221: mv.visitVarInsn(Opcodes.ILOAD
1222: + (opcode >> 2), opcode & 0x3);
1223: }
1224: v += 1;
1225: break;
1226: case ClassWriter.LABEL_INSN:
1227: mv.visitJumpInsn(opcode, labels[w
1228: + readShort(v + 1)]);
1229: v += 3;
1230: break;
1231: case ClassWriter.LABELW_INSN:
1232: mv.visitJumpInsn(opcode - 33, labels[w
1233: + readInt(v + 1)]);
1234: v += 5;
1235: break;
1236: case ClassWriter.WIDE_INSN:
1237: opcode = b[v + 1] & 0xFF;
1238: if (opcode == Opcodes.IINC) {
1239: mv.visitIincInsn(readUnsignedShort(v + 2),
1240: readShort(v + 4));
1241: v += 6;
1242: } else {
1243: mv.visitVarInsn(opcode,
1244: readUnsignedShort(v + 2));
1245: v += 4;
1246: }
1247: break;
1248: case ClassWriter.TABL_INSN:
1249: // skips 0 to 3 padding bytes
1250: v = v + 4 - (w & 3);
1251: // reads instruction
1252: label = w + readInt(v);
1253: int min = readInt(v + 4);
1254: int max = readInt(v + 8);
1255: v += 12;
1256: Label[] table = new Label[max - min + 1];
1257: for (j = 0; j < table.length; ++j) {
1258: table[j] = labels[w + readInt(v)];
1259: v += 4;
1260: }
1261: mv.visitTableSwitchInsn(min, max,
1262: labels[label], table);
1263: break;
1264: case ClassWriter.LOOK_INSN:
1265: // skips 0 to 3 padding bytes
1266: v = v + 4 - (w & 3);
1267: // reads instruction
1268: label = w + readInt(v);
1269: j = readInt(v + 4);
1270: v += 8;
1271: int[] keys = new int[j];
1272: Label[] values = new Label[j];
1273: for (j = 0; j < keys.length; ++j) {
1274: keys[j] = readInt(v);
1275: values[j] = labels[w + readInt(v + 4)];
1276: v += 8;
1277: }
1278: mv.visitLookupSwitchInsn(labels[label], keys,
1279: values);
1280: break;
1281: case ClassWriter.VAR_INSN:
1282: mv.visitVarInsn(opcode, b[v + 1] & 0xFF);
1283: v += 2;
1284: break;
1285: case ClassWriter.SBYTE_INSN:
1286: mv.visitIntInsn(opcode, b[v + 1]);
1287: v += 2;
1288: break;
1289: case ClassWriter.SHORT_INSN:
1290: mv.visitIntInsn(opcode, readShort(v + 1));
1291: v += 3;
1292: break;
1293: case ClassWriter.LDC_INSN:
1294: mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
1295: v += 2;
1296: break;
1297: case ClassWriter.LDCW_INSN:
1298: mv.visitLdcInsn(readConst(
1299: readUnsignedShort(v + 1), c));
1300: v += 3;
1301: break;
1302: case ClassWriter.FIELDORMETH_INSN:
1303: case ClassWriter.ITFMETH_INSN:
1304: int cpIndex = items[readUnsignedShort(v + 1)];
1305: String iowner = readClass(cpIndex, c);
1306: cpIndex = items[readUnsignedShort(cpIndex + 2)];
1307: String iname = readUTF8(cpIndex, c);
1308: String idesc = readUTF8(cpIndex + 2, c);
1309: if (opcode < Opcodes.INVOKEVIRTUAL) {
1310: mv.visitFieldInsn(opcode, iowner, iname,
1311: idesc);
1312: } else {
1313: mv.visitMethodInsn(opcode, iowner, iname,
1314: idesc);
1315: }
1316: if (opcode == Opcodes.INVOKEINTERFACE) {
1317: v += 5;
1318: } else {
1319: v += 3;
1320: }
1321: break;
1322: case ClassWriter.TYPE_INSN:
1323: mv.visitTypeInsn(opcode, readClass(v + 1, c));
1324: v += 3;
1325: break;
1326: case ClassWriter.IINC_INSN:
1327: mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
1328: v += 3;
1329: break;
1330: // case MANA_INSN:
1331: default:
1332: mv.visitMultiANewArrayInsn(readClass(v + 1, c),
1333: b[v + 3] & 0xFF);
1334: v += 4;
1335: break;
1336: }
1337: }
1338: l = labels[codeEnd - codeStart];
1339: if (l != null) {
1340: mv.visitLabel(l);
1341: }
1342: // visits the local variable tables
1343: if (!skipDebug && varTable != 0) {
1344: int[] typeTable = null;
1345: if (varTypeTable != 0) {
1346: k = readUnsignedShort(varTypeTable) * 3;
1347: w = varTypeTable + 2;
1348: typeTable = new int[k];
1349: while (k > 0) {
1350: typeTable[--k] = w + 6; // signature
1351: typeTable[--k] = readUnsignedShort(w + 8); // index
1352: typeTable[--k] = readUnsignedShort(w); // start
1353: w += 10;
1354: }
1355: }
1356: k = readUnsignedShort(varTable);
1357: w = varTable + 2;
1358: for (; k > 0; --k) {
1359: int start = readUnsignedShort(w);
1360: int length = readUnsignedShort(w + 2);
1361: int index = readUnsignedShort(w + 8);
1362: String vsignature = null;
1363: if (typeTable != null) {
1364: for (int a = 0; a < typeTable.length; a += 3) {
1365: if (typeTable[a] == start
1366: && typeTable[a + 1] == index) {
1367: vsignature = readUTF8(
1368: typeTable[a + 2], c);
1369: break;
1370: }
1371: }
1372: }
1373: mv.visitLocalVariable(readUTF8(w + 4, c),
1374: readUTF8(w + 6, c), vsignature,
1375: labels[start], labels[start + length],
1376: index);
1377: w += 10;
1378: }
1379: }
1380: // visits the other attributes
1381: while (cattrs != null) {
1382: attr = cattrs.next;
1383: cattrs.next = null;
1384: mv.visitAttribute(cattrs);
1385: cattrs = attr;
1386: }
1387: // visits the max stack and max locals values
1388: mv.visitMaxs(maxStack, maxLocals);
1389: }
1390:
1391: if (mv != null) {
1392: mv.visitEnd();
1393: }
1394: }
1395:
1396: // visits the end of the class
1397: classVisitor.visitEnd();
1398: }
1399:
1400: /**
1401: * Reads parameter annotations and makes the given visitor visit them.
1402: *
1403: * @param v start offset in {@link #b b} of the annotations to be read.
1404: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1405: * {@link #readClass(int,char[]) readClass} or
1406: * {@link #readConst readConst}.
1407: * @param visible <tt>true</tt> if the annotations to be read are visible
1408: * at runtime.
1409: * @param mv the visitor that must visit the annotations.
1410: */
1411: private void readParameterAnnotations(int v, final char[] buf,
1412: final boolean visible, final MethodVisitor mv) {
1413: int n = b[v++] & 0xFF;
1414: for (int i = 0; i < n; ++i) {
1415: int j = readUnsignedShort(v);
1416: v += 2;
1417: for (; j > 0; --j) {
1418: v = readAnnotationValues(v + 2, buf, true, mv
1419: .visitParameterAnnotation(i, readUTF8(v, buf),
1420: visible));
1421: }
1422: }
1423: }
1424:
1425: /**
1426: * Reads the values of an annotation and makes the given visitor visit them.
1427: *
1428: * @param v the start offset in {@link #b b} of the values to be read
1429: * (including the unsigned short that gives the number of values).
1430: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1431: * {@link #readClass(int,char[]) readClass} or
1432: * {@link #readConst readConst}.
1433: * @param named if the annotation values are named or not.
1434: * @param av the visitor that must visit the values.
1435: * @return the end offset of the annotation values.
1436: */
1437: private int readAnnotationValues(int v, final char[] buf,
1438: final boolean named, final AnnotationVisitor av) {
1439: int i = readUnsignedShort(v);
1440: v += 2;
1441: if (named) {
1442: for (; i > 0; --i) {
1443: v = readAnnotationValue(v + 2, buf, readUTF8(v, buf),
1444: av);
1445: }
1446: } else {
1447: for (; i > 0; --i) {
1448: v = readAnnotationValue(v, buf, null, av);
1449: }
1450: }
1451: if (av != null) {
1452: av.visitEnd();
1453: }
1454: return v;
1455: }
1456:
1457: /**
1458: * Reads a value of an annotation and makes the given visitor visit it.
1459: *
1460: * @param v the start offset in {@link #b b} of the value to be read (<i>not
1461: * including the value name constant pool index</i>).
1462: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1463: * {@link #readClass(int,char[]) readClass} or
1464: * {@link #readConst readConst}.
1465: * @param name the name of the value to be read.
1466: * @param av the visitor that must visit the value.
1467: * @return the end offset of the annotation value.
1468: */
1469: private int readAnnotationValue(int v, final char[] buf,
1470: final String name, final AnnotationVisitor av) {
1471: int i;
1472: if (av == null) {
1473: switch (b[v] & 0xFF) {
1474: case 'e': // enum_const_value
1475: return v + 5;
1476: case '@': // annotation_value
1477: return readAnnotationValues(v + 3, buf, true, null);
1478: case '[': // array_value
1479: return readAnnotationValues(v + 1, buf, false, null);
1480: default:
1481: return v + 3;
1482: }
1483: }
1484: switch (b[v++] & 0xFF) {
1485: case 'I': // pointer to CONSTANT_Integer
1486: case 'J': // pointer to CONSTANT_Long
1487: case 'F': // pointer to CONSTANT_Float
1488: case 'D': // pointer to CONSTANT_Double
1489: av.visit(name, readConst(readUnsignedShort(v), buf));
1490: v += 2;
1491: break;
1492: case 'B': // pointer to CONSTANT_Byte
1493: av.visit(name, new Byte(
1494: (byte) readInt(items[readUnsignedShort(v)])));
1495: v += 2;
1496: break;
1497: case 'Z': // pointer to CONSTANT_Boolean
1498: av
1499: .visit(
1500: name,
1501: readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE
1502: : Boolean.TRUE);
1503: v += 2;
1504: break;
1505: case 'S': // pointer to CONSTANT_Short
1506: av.visit(name, new Short(
1507: (short) readInt(items[readUnsignedShort(v)])));
1508: v += 2;
1509: break;
1510: case 'C': // pointer to CONSTANT_Char
1511: av.visit(name, new Character(
1512: (char) readInt(items[readUnsignedShort(v)])));
1513: v += 2;
1514: break;
1515: case 's': // pointer to CONSTANT_Utf8
1516: av.visit(name, readUTF8(v, buf));
1517: v += 2;
1518: break;
1519: case 'e': // enum_const_value
1520: av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
1521: v += 4;
1522: break;
1523: case 'c': // class_info
1524: av.visit(name, Type.getType(readUTF8(v, buf)));
1525: v += 2;
1526: break;
1527: case '@': // annotation_value
1528: v = readAnnotationValues(v + 2, buf, true, av
1529: .visitAnnotation(name, readUTF8(v, buf)));
1530: break;
1531: case '[': // array_value
1532: int size = readUnsignedShort(v);
1533: v += 2;
1534: if (size == 0) {
1535: return readAnnotationValues(v - 2, buf, false, av
1536: .visitArray(name));
1537: }
1538: switch (this .b[v++] & 0xFF) {
1539: case 'B':
1540: byte[] bv = new byte[size];
1541: for (i = 0; i < size; i++) {
1542: bv[i] = (byte) readInt(items[readUnsignedShort(v)]);
1543: v += 3;
1544: }
1545: av.visit(name, bv);
1546: --v;
1547: break;
1548: case 'Z':
1549: boolean[] zv = new boolean[size];
1550: for (i = 0; i < size; i++) {
1551: zv[i] = readInt(items[readUnsignedShort(v)]) != 0;
1552: v += 3;
1553: }
1554: av.visit(name, zv);
1555: --v;
1556: break;
1557: case 'S':
1558: short[] sv = new short[size];
1559: for (i = 0; i < size; i++) {
1560: sv[i] = (short) readInt(items[readUnsignedShort(v)]);
1561: v += 3;
1562: }
1563: av.visit(name, sv);
1564: --v;
1565: break;
1566: case 'C':
1567: char[] cv = new char[size];
1568: for (i = 0; i < size; i++) {
1569: cv[i] = (char) readInt(items[readUnsignedShort(v)]);
1570: v += 3;
1571: }
1572: av.visit(name, cv);
1573: --v;
1574: break;
1575: case 'I':
1576: int[] iv = new int[size];
1577: for (i = 0; i < size; i++) {
1578: iv[i] = readInt(items[readUnsignedShort(v)]);
1579: v += 3;
1580: }
1581: av.visit(name, iv);
1582: --v;
1583: break;
1584: case 'J':
1585: long[] lv = new long[size];
1586: for (i = 0; i < size; i++) {
1587: lv[i] = readLong(items[readUnsignedShort(v)]);
1588: v += 3;
1589: }
1590: av.visit(name, lv);
1591: --v;
1592: break;
1593: case 'F':
1594: float[] fv = new float[size];
1595: for (i = 0; i < size; i++) {
1596: fv[i] = Float
1597: .intBitsToFloat(readInt(items[readUnsignedShort(v)]));
1598: v += 3;
1599: }
1600: av.visit(name, fv);
1601: --v;
1602: break;
1603: case 'D':
1604: double[] dv = new double[size];
1605: for (i = 0; i < size; i++) {
1606: dv[i] = Double
1607: .longBitsToDouble(readLong(items[readUnsignedShort(v)]));
1608: v += 3;
1609: }
1610: av.visit(name, dv);
1611: --v;
1612: break;
1613: default:
1614: v = readAnnotationValues(v - 3, buf, false, av
1615: .visitArray(name));
1616: }
1617: }
1618: return v;
1619: }
1620:
1621: private int readFrameType(final Object[] frame, final int index,
1622: int v, final char[] buf, final Label[] labels) {
1623: int type = b[v++] & 0xFF;
1624: switch (type) {
1625: case 0:
1626: frame[index] = Opcodes.TOP;
1627: break;
1628: case 1:
1629: frame[index] = Opcodes.INTEGER;
1630: break;
1631: case 2:
1632: frame[index] = Opcodes.FLOAT;
1633: break;
1634: case 3:
1635: frame[index] = Opcodes.DOUBLE;
1636: break;
1637: case 4:
1638: frame[index] = Opcodes.LONG;
1639: break;
1640: case 5:
1641: frame[index] = Opcodes.NULL;
1642: break;
1643: case 6:
1644: frame[index] = Opcodes.UNINITIALIZED_THIS;
1645: break;
1646: case 7: // Object
1647: frame[index] = readClass(v, buf);
1648: v += 2;
1649: break;
1650: default: // Uninitialized
1651: int offset = readUnsignedShort(v);
1652: if (labels[offset] == null) {
1653: labels[offset] = new Label();
1654: }
1655: frame[index] = labels[offset];
1656: v += 2;
1657: }
1658: return v;
1659: }
1660:
1661: /**
1662: * Reads an attribute in {@link #b b}.
1663: *
1664: * @param attrs prototypes of the attributes that must be parsed during the
1665: * visit of the class. Any attribute whose type is not equal to the
1666: * type of one the prototypes is ignored (i.e. an empty
1667: * {@link Attribute} instance is returned).
1668: * @param type the type of the attribute.
1669: * @param off index of the first byte of the attribute's content in
1670: * {@link #b b}. The 6 attribute header bytes, containing the type
1671: * and the length of the attribute, are not taken into account here
1672: * (they have already been read).
1673: * @param len the length of the attribute's content.
1674: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1675: * {@link #readClass(int,char[]) readClass} or
1676: * {@link #readConst readConst}.
1677: * @param codeOff index of the first byte of code's attribute content in
1678: * {@link #b b}, or -1 if the attribute to be read is not a code
1679: * attribute. The 6 attribute header bytes, containing the type and
1680: * the length of the attribute, are not taken into account here.
1681: * @param labels the labels of the method's code, or <tt>null</tt> if the
1682: * attribute to be read is not a code attribute.
1683: * @return the attribute that has been read, or <tt>null</tt> to skip this
1684: * attribute.
1685: */
1686: private Attribute readAttribute(final Attribute[] attrs,
1687: final String type, final int off, final int len,
1688: final char[] buf, final int codeOff, final Label[] labels) {
1689: for (int i = 0; i < attrs.length; ++i) {
1690: if (attrs[i].type.equals(type)) {
1691: return attrs[i].read(this , off, len, buf, codeOff,
1692: labels);
1693: }
1694: }
1695: return new Attribute(type).read(this , off, len, null, -1, null);
1696: }
1697:
1698: // ------------------------------------------------------------------------
1699: // Utility methods: low level parsing
1700: // ------------------------------------------------------------------------
1701:
1702: /**
1703: * Returns the start index of the constant pool item in {@link #b b}, plus
1704: * one. <i>This method is intended for {@link Attribute} sub classes, and is
1705: * normally not needed by class generators or adapters.</i>
1706: *
1707: * @param item the index a constant pool item.
1708: * @return the start index of the constant pool item in {@link #b b}, plus
1709: * one.
1710: */
1711: public int getItem(final int item) {
1712: return items[item];
1713: }
1714:
1715: /**
1716: * Reads a byte value in {@link #b b}. <i>This method is intended for
1717: * {@link Attribute} sub classes, and is normally not needed by class
1718: * generators or adapters.</i>
1719: *
1720: * @param index the start index of the value to be read in {@link #b b}.
1721: * @return the read value.
1722: */
1723: public int readByte(final int index) {
1724: return b[index] & 0xFF;
1725: }
1726:
1727: /**
1728: * Reads an unsigned short value in {@link #b b}. <i>This method is
1729: * intended for {@link Attribute} sub classes, and is normally not needed by
1730: * class generators or adapters.</i>
1731: *
1732: * @param index the start index of the value to be read in {@link #b b}.
1733: * @return the read value.
1734: */
1735: public int readUnsignedShort(final int index) {
1736: byte[] b = this .b;
1737: return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
1738: }
1739:
1740: /**
1741: * Reads a signed short value in {@link #b b}. <i>This method is intended
1742: * for {@link Attribute} sub classes, and is normally not needed by class
1743: * generators or adapters.</i>
1744: *
1745: * @param index the start index of the value to be read in {@link #b b}.
1746: * @return the read value.
1747: */
1748: public short readShort(final int index) {
1749: byte[] b = this .b;
1750: return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
1751: }
1752:
1753: /**
1754: * Reads a signed int value in {@link #b b}. <i>This method is intended for
1755: * {@link Attribute} sub classes, and is normally not needed by class
1756: * generators or adapters.</i>
1757: *
1758: * @param index the start index of the value to be read in {@link #b b}.
1759: * @return the read value.
1760: */
1761: public int readInt(final int index) {
1762: byte[] b = this .b;
1763: return ((b[index] & 0xFF) << 24)
1764: | ((b[index + 1] & 0xFF) << 16)
1765: | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
1766: }
1767:
1768: /**
1769: * Reads a signed long value in {@link #b b}. <i>This method is intended
1770: * for {@link Attribute} sub classes, and is normally not needed by class
1771: * generators or adapters.</i>
1772: *
1773: * @param index the start index of the value to be read in {@link #b b}.
1774: * @return the read value.
1775: */
1776: public long readLong(final int index) {
1777: long l1 = readInt(index);
1778: long l0 = readInt(index + 4) & 0xFFFFFFFFL;
1779: return (l1 << 32) | l0;
1780: }
1781:
1782: /**
1783: * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method
1784: * is intended for {@link Attribute} sub classes, and is normally not needed
1785: * by class generators or adapters.</i>
1786: *
1787: * @param index the start index of an unsigned short value in {@link #b b},
1788: * whose value is the index of an UTF8 constant pool item.
1789: * @param buf buffer to be used to read the item. This buffer must be
1790: * sufficiently large. It is not automatically resized.
1791: * @return the String corresponding to the specified UTF8 item.
1792: */
1793: public String readUTF8(int index, final char[] buf) {
1794: int item = readUnsignedShort(index);
1795: String s = strings[item];
1796: if (s != null) {
1797: return s;
1798: }
1799: index = items[item];
1800: return strings[item] = readUTF(index + 2,
1801: readUnsignedShort(index), buf);
1802: }
1803:
1804: /**
1805: * Reads UTF8 string in {@link #b b}.
1806: *
1807: * @param index start offset of the UTF8 string to be read.
1808: * @param utfLen length of the UTF8 string to be read.
1809: * @param buf buffer to be used to read the string. This buffer must be
1810: * sufficiently large. It is not automatically resized.
1811: * @return the String corresponding to the specified UTF8 string.
1812: */
1813: private String readUTF(int index, final int utfLen, final char[] buf) {
1814: int endIndex = index + utfLen;
1815: byte[] b = this .b;
1816: int strLen = 0;
1817: int c, d, e;
1818: while (index < endIndex) {
1819: c = b[index++] & 0xFF;
1820: switch (c >> 4) {
1821: case 0:
1822: case 1:
1823: case 2:
1824: case 3:
1825: case 4:
1826: case 5:
1827: case 6:
1828: case 7:
1829: // 0xxxxxxx
1830: buf[strLen++] = (char) c;
1831: break;
1832: case 12:
1833: case 13:
1834: // 110x xxxx 10xx xxxx
1835: d = b[index++];
1836: buf[strLen++] = (char) (((c & 0x1F) << 6) | (d & 0x3F));
1837: break;
1838: default:
1839: // 1110 xxxx 10xx xxxx 10xx xxxx
1840: d = b[index++];
1841: e = b[index++];
1842: buf[strLen++] = (char) (((c & 0x0F) << 12)
1843: | ((d & 0x3F) << 6) | (e & 0x3F));
1844: break;
1845: }
1846: }
1847: return new String(buf, 0, strLen);
1848: }
1849:
1850: /**
1851: * Reads a class constant pool item in {@link #b b}. <i>This method is
1852: * intended for {@link Attribute} sub classes, and is normally not needed by
1853: * class generators or adapters.</i>
1854: *
1855: * @param index the start index of an unsigned short value in {@link #b b},
1856: * whose value is the index of a class constant pool item.
1857: * @param buf buffer to be used to read the item. This buffer must be
1858: * sufficiently large. It is not automatically resized.
1859: * @return the String corresponding to the specified class item.
1860: */
1861: public String readClass(final int index, final char[] buf) {
1862: // computes the start index of the CONSTANT_Class item in b
1863: // and reads the CONSTANT_Utf8 item designated by
1864: // the first two bytes of this CONSTANT_Class item
1865: return readUTF8(items[readUnsignedShort(index)], buf);
1866: }
1867:
1868: /**
1869: * Reads a numeric or string constant pool item in {@link #b b}. <i>This
1870: * method is intended for {@link Attribute} sub classes, and is normally not
1871: * needed by class generators or adapters.</i>
1872: *
1873: * @param item the index of a constant pool item.
1874: * @param buf buffer to be used to read the item. This buffer must be
1875: * sufficiently large. It is not automatically resized.
1876: * @return the {@link Integer}, {@link Float}, {@link Long},
1877: * {@link Double}, {@link String} or {@link Type} corresponding to
1878: * the given constant pool item.
1879: */
1880: public Object readConst(final int item, final char[] buf) {
1881: int index = items[item];
1882: switch (b[index - 1]) {
1883: case ClassWriter.INT:
1884: return new Integer(readInt(index));
1885: case ClassWriter.FLOAT:
1886: return new Float(Float.intBitsToFloat(readInt(index)));
1887: case ClassWriter.LONG:
1888: return new Long(readLong(index));
1889: case ClassWriter.DOUBLE:
1890: return new Double(Double.longBitsToDouble(readLong(index)));
1891: case ClassWriter.CLASS:
1892: String s = readUTF8(index, buf);
1893: return s.charAt(0) == '[' ? Type.getType(s) : Type
1894: .getObjectType(s);
1895: // case ClassWriter.STR:
1896: default:
1897: return readUTF8(index, buf);
1898: }
1899: }
1900: }
|