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