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