Mercurial > lasercutter
view src/clojure/asm/ClassReader.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 /***2 * ASM: a very small and fast Java bytecode manipulation framework3 * Copyright (c) 2000-2005 INRIA, France Telecom4 * All rights reserved.5 *6 * Redistribution and use in source and binary forms, with or without7 * modification, are permitted provided that the following conditions8 * are met:9 * 1. Redistributions of source code must retain the above copyright10 * notice, this list of conditions and the following disclaimer.11 * 2. Redistributions in binary form must reproduce the above copyright12 * notice, this list of conditions and the following disclaimer in the13 * documentation and/or other materials provided with the distribution.14 * 3. Neither the name of the copyright holders nor the names of its15 * contributors may be used to endorse or promote products derived from16 * this software without specific prior written permission.17 *18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF28 * THE POSSIBILITY OF SUCH DAMAGE.29 */30 package clojure.asm;32 import java.io.InputStream;33 import java.io.IOException;35 /**36 * A Java class parser to make a {@link ClassVisitor} visit an existing class.37 * This class parses a byte array conforming to the Java class file format and38 * calls the appropriate visit methods of a given class visitor for each field,39 * method and bytecode instruction encountered.40 *41 * @author Eric Bruneton42 * @author Eugene Kuleshov43 */44 public class ClassReader{46 /**47 * Flag to skip method code. If this class is set <code>CODE</code>48 * attribute won't be visited. This can be used, for example, to retrieve49 * annotations for methods and method parameters.50 */51 public final static int SKIP_CODE = 1;53 /**54 * Flag to skip the debug information in the class. If this flag is set the55 * debug information of the class is not visited, i.e. the56 * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and57 * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be58 * called.59 */60 public final static int SKIP_DEBUG = 2;62 /**63 * Flag to skip the stack map frames in the class. If this flag is set the64 * stack map frames of the class is not visited, i.e. the65 * {@link MethodVisitor#visitFrame visitFrame} method will not be called.66 * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is67 * used: it avoids visiting frames that will be ignored and recomputed from68 * scratch in the class writer.69 */70 public final static int SKIP_FRAMES = 4;72 /**73 * Flag to expand the stack map frames. By default stack map frames are74 * visited in their original format (i.e. "expanded" for classes whose75 * version is less than V1_6, and "compressed" for the other classes). If76 * this flag is set, stack map frames are always visited in expanded format77 * (this option adds a decompression/recompression step in ClassReader and78 * ClassWriter which degrades performances quite a lot).79 */80 public final static int EXPAND_FRAMES = 8;82 /**83 * The class to be parsed. <i>The content of this array must not be84 * modified. This field is intended for {@link Attribute} sub classes, and85 * is normally not needed by class generators or adapters.</i>86 */87 public final byte[] b;89 /**90 * The start index of each constant pool item in {@link #b b}, plus one.91 * The one byte offset skips the constant pool item tag that indicates its92 * type.93 */94 private final int[] items;96 /**97 * The String objects corresponding to the CONSTANT_Utf8 items. This cache98 * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,99 * which GREATLY improves performances (by a factor 2 to 3). This caching100 * strategy could be extended to all constant pool items, but its benefit101 * would not be so great for these items (because they are much less102 * expensive to parse than CONSTANT_Utf8 items).103 */104 private final String[] strings;106 /**107 * Maximum length of the strings contained in the constant pool of the108 * class.109 */110 private final int maxStringLength;112 /**113 * Start index of the class header information (access, name...) in114 * {@link #b b}.115 */116 public final int header;118 // ------------------------------------------------------------------------119 // Constructors120 // ------------------------------------------------------------------------122 /**123 * Constructs a new {@link ClassReader} object.124 *125 * @param b the bytecode of the class to be read.126 */127 public ClassReader(final byte[] b){128 this(b, 0, b.length);129 }131 /**132 * Constructs a new {@link ClassReader} object.133 *134 * @param b the bytecode of the class to be read.135 * @param off the start offset of the class data.136 * @param len the length of the class data.137 */138 public ClassReader(final byte[] b, final int off, final int len){139 this.b = b;140 // parses the constant pool141 items = new int[readUnsignedShort(off + 8)];142 int n = items.length;143 strings = new String[n];144 int max = 0;145 int index = off + 10;146 for(int i = 1; i < n; ++i)147 {148 items[i] = index + 1;149 int size;150 switch(b[index])151 {152 case ClassWriter.FIELD:153 case ClassWriter.METH:154 case ClassWriter.IMETH:155 case ClassWriter.INT:156 case ClassWriter.FLOAT:157 case ClassWriter.NAME_TYPE:158 size = 5;159 break;160 case ClassWriter.LONG:161 case ClassWriter.DOUBLE:162 size = 9;163 ++i;164 break;165 case ClassWriter.UTF8:166 size = 3 + readUnsignedShort(index + 1);167 if(size > max)168 {169 max = size;170 }171 break;172 // case ClassWriter.CLASS:173 // case ClassWriter.STR:174 default:175 size = 3;176 break;177 }178 index += size;179 }180 maxStringLength = max;181 // the class header information starts just after the constant pool182 header = index;183 }185 /**186 * Returns the class's access flags (see {@link Opcodes}). This value may187 * not reflect Deprecated and Synthetic flags when bytecode is before 1.5188 * and those flags are represented by attributes.189 *190 * @return the class access flags191 * @see ClassVisitor#visit(int,int,String,String,String,String[])192 */193 public int getAccess(){194 return readUnsignedShort(header);195 }197 /**198 * Returns the internal name of the class (see199 * {@link Type#getInternalName() getInternalName}).200 *201 * @return the internal class name202 * @see ClassVisitor#visit(int,int,String,String,String,String[])203 */204 public String getClassName(){205 return readClass(header + 2, new char[maxStringLength]);206 }208 /**209 * Returns the internal of name of the super class (see210 * {@link Type#getInternalName() getInternalName}). For interfaces, the211 * super class is {@link Object}.212 *213 * @return the internal name of super class, or <tt>null</tt> for214 * {@link Object} class.215 * @see ClassVisitor#visit(int,int,String,String,String,String[])216 */217 public String getSuperName(){218 int n = items[readUnsignedShort(header + 4)];219 return n == 0 ? null : readUTF8(n, new char[maxStringLength]);220 }222 /**223 * Returns the internal names of the class's interfaces (see224 * {@link Type#getInternalName() getInternalName}).225 *226 * @return the array of internal names for all implemented interfaces or227 * <tt>null</tt>.228 * @see ClassVisitor#visit(int,int,String,String,String,String[])229 */230 public String[] getInterfaces(){231 int index = header + 6;232 int n = readUnsignedShort(index);233 String[] interfaces = new String[n];234 if(n > 0)235 {236 char[] buf = new char[maxStringLength];237 for(int i = 0; i < n; ++i)238 {239 index += 2;240 interfaces[i] = readClass(index, buf);241 }242 }243 return interfaces;244 }246 /**247 * Copies the constant pool data into the given {@link ClassWriter}. Should248 * be called before the {@link #accept(ClassVisitor,int)} method.249 *250 * @param classWriter the {@link ClassWriter} to copy constant pool into.251 */252 void copyPool(final ClassWriter classWriter){253 char[] buf = new char[maxStringLength];254 int ll = items.length;255 Item[] items2 = new Item[ll];256 for(int i = 1; i < ll; i++)257 {258 int index = items[i];259 int tag = b[index - 1];260 Item item = new Item(i);261 int nameType;262 switch(tag)263 {264 case ClassWriter.FIELD:265 case ClassWriter.METH:266 case ClassWriter.IMETH:267 nameType = items[readUnsignedShort(index + 2)];268 item.set(tag,269 readClass(index, buf),270 readUTF8(nameType, buf),271 readUTF8(nameType + 2, buf));272 break;274 case ClassWriter.INT:275 item.set(readInt(index));276 break;278 case ClassWriter.FLOAT:279 item.set(Float.intBitsToFloat(readInt(index)));280 break;282 case ClassWriter.NAME_TYPE:283 item.set(tag,284 readUTF8(index, buf),285 readUTF8(index + 2, buf),286 null);287 break;289 case ClassWriter.LONG:290 item.set(readLong(index));291 ++i;292 break;294 case ClassWriter.DOUBLE:295 item.set(Double.longBitsToDouble(readLong(index)));296 ++i;297 break;299 case ClassWriter.UTF8:300 {301 String s = strings[i];302 if(s == null)303 {304 index = items[i];305 s = strings[i] = readUTF(index + 2,306 readUnsignedShort(index),307 buf);308 }309 item.set(tag, s, null, null);310 }311 break;313 // case ClassWriter.STR:314 // case ClassWriter.CLASS:315 default:316 item.set(tag, readUTF8(index, buf), null, null);317 break;318 }320 int index2 = item.hashCode % items2.length;321 item.next = items2[index2];322 items2[index2] = item;323 }325 int off = items[1] - 1;326 classWriter.pool.putByteArray(b, off, header - off);327 classWriter.items = items2;328 classWriter.threshold = (int) (0.75d * ll);329 classWriter.index = ll;330 }332 /**333 * Constructs a new {@link ClassReader} object.334 *335 * @param is an input stream from which to read the class.336 * @throws IOException if a problem occurs during reading.337 */338 public ClassReader(final InputStream is) throws IOException{339 this(readClass(is));340 }342 /**343 * Constructs a new {@link ClassReader} object.344 *345 * @param name the fully qualified name of the class to be read.346 * @throws IOException if an exception occurs during reading.347 */348 public ClassReader(final String name) throws IOException{349 this(ClassLoader.getSystemResourceAsStream(name.replace('.', '/')350 + ".class"));351 }353 /**354 * Reads the bytecode of a class.355 *356 * @param is an input stream from which to read the class.357 * @return the bytecode read from the given input stream.358 * @throws IOException if a problem occurs during reading.359 */360 private static byte[] readClass(final InputStream is) throws IOException{361 if(is == null)362 {363 throw new IOException("Class not found");364 }365 byte[] b = new byte[is.available()];366 int len = 0;367 while(true)368 {369 int n = is.read(b, len, b.length - len);370 if(n == -1)371 {372 if(len < b.length)373 {374 byte[] c = new byte[len];375 System.arraycopy(b, 0, c, 0, len);376 b = c;377 }378 return b;379 }380 len += n;381 if(len == b.length)382 {383 byte[] c = new byte[b.length + 1000];384 System.arraycopy(b, 0, c, 0, len);385 b = c;386 }387 }388 }390 // ------------------------------------------------------------------------391 // Public methods392 // ------------------------------------------------------------------------394 /**395 * Makes the given visitor visit the Java class of this {@link ClassReader}.396 * This class is the one specified in the constructor (see397 * {@link #ClassReader(byte[]) ClassReader}).398 *399 * @param classVisitor the visitor that must visit this class.400 * @param flags option flags that can be used to modify the default behavior401 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}.402 */403 public void accept(final ClassVisitor classVisitor, final int flags){404 accept(classVisitor, new Attribute[0], flags);405 }407 /**408 * Makes the given visitor visit the Java class of this {@link ClassReader}.409 * This class is the one specified in the constructor (see410 * {@link #ClassReader(byte[]) ClassReader}).411 *412 * @param classVisitor the visitor that must visit this class.413 * @param attrs prototypes of the attributes that must be parsed during the414 * visit of the class. Any attribute whose type is not equal to the415 * type of one the prototypes will not be parsed: its byte array416 * value will be passed unchanged to the ClassWriter. <i>This may417 * corrupt it if this value contains references to the constant pool,418 * or has syntactic or semantic links with a class element that has419 * been transformed by a class adapter between the reader and the420 * writer</i>.421 * @param flags option flags that can be used to modify the default behavior422 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}.423 */424 public void accept(425 final ClassVisitor classVisitor,426 final Attribute[] attrs,427 final int flags){428 byte[] b = this.b; // the bytecode array429 char[] c = new char[maxStringLength]; // buffer used to read strings430 int i, j, k; // loop variables431 int u, v, w; // indexes in b432 Attribute attr;434 int access;435 String name;436 String desc;437 String attrName;438 String signature;439 int anns = 0;440 int ianns = 0;441 Attribute cattrs = null;443 // visits the header444 u = header;445 access = readUnsignedShort(u);446 name = readClass(u + 2, c);447 v = items[readUnsignedShort(u + 4)];448 String superClassName = v == 0 ? null : readUTF8(v, c);449 String[] implementedItfs = new String[readUnsignedShort(u + 6)];450 w = 0;451 u += 8;452 for(i = 0; i < implementedItfs.length; ++i)453 {454 implementedItfs[i] = readClass(u, c);455 u += 2;456 }458 boolean skipCode = (flags & SKIP_CODE) != 0;459 boolean skipDebug = (flags & SKIP_DEBUG) != 0;460 boolean unzip = (flags & EXPAND_FRAMES) != 0;462 // skips fields and methods463 v = u;464 i = readUnsignedShort(v);465 v += 2;466 for(; i > 0; --i)467 {468 j = readUnsignedShort(v + 6);469 v += 8;470 for(; j > 0; --j)471 {472 v += 6 + readInt(v + 2);473 }474 }475 i = readUnsignedShort(v);476 v += 2;477 for(; i > 0; --i)478 {479 j = readUnsignedShort(v + 6);480 v += 8;481 for(; j > 0; --j)482 {483 v += 6 + readInt(v + 2);484 }485 }486 // reads the class's attributes487 signature = null;488 String sourceFile = null;489 String sourceDebug = null;490 String enclosingOwner = null;491 String enclosingName = null;492 String enclosingDesc = null;494 i = readUnsignedShort(v);495 v += 2;496 for(; i > 0; --i)497 {498 attrName = readUTF8(v, c);499 // tests are sorted in decreasing frequency order500 // (based on frequencies observed on typical classes)501 if(attrName.equals("SourceFile"))502 {503 sourceFile = readUTF8(v + 6, c);504 }505 else if(attrName.equals("InnerClasses"))506 {507 w = v + 6;508 }509 else if(attrName.equals("EnclosingMethod"))510 {511 enclosingOwner = readClass(v + 6, c);512 int item = readUnsignedShort(v + 8);513 if(item != 0)514 {515 enclosingName = readUTF8(items[item], c);516 enclosingDesc = readUTF8(items[item] + 2, c);517 }518 }519 else if(attrName.equals("Signature"))520 {521 signature = readUTF8(v + 6, c);522 }523 else if(attrName.equals("RuntimeVisibleAnnotations"))524 {525 anns = v + 6;526 }527 else if(attrName.equals("Deprecated"))528 {529 access |= Opcodes.ACC_DEPRECATED;530 }531 else if(attrName.equals("Synthetic"))532 {533 access |= Opcodes.ACC_SYNTHETIC;534 }535 else if(attrName.equals("SourceDebugExtension"))536 {537 int len = readInt(v + 2);538 sourceDebug = readUTF(v + 6, len, new char[len]);539 }540 else if(attrName.equals("RuntimeInvisibleAnnotations"))541 {542 ianns = v + 6;543 }544 else545 {546 attr = readAttribute(attrs,547 attrName,548 v + 6,549 readInt(v + 2),550 c,551 -1,552 null);553 if(attr != null)554 {555 attr.next = cattrs;556 cattrs = attr;557 }558 }559 v += 6 + readInt(v + 2);560 }561 // calls the visit method562 classVisitor.visit(readInt(4),563 access,564 name,565 signature,566 superClassName,567 implementedItfs);569 // calls the visitSource method570 if(!skipDebug && (sourceFile != null || sourceDebug != null))571 {572 classVisitor.visitSource(sourceFile, sourceDebug);573 }575 // calls the visitOuterClass method576 if(enclosingOwner != null)577 {578 classVisitor.visitOuterClass(enclosingOwner,579 enclosingName,580 enclosingDesc);581 }583 // visits the class annotations584 for(i = 1; i >= 0; --i)585 {586 v = i == 0 ? ianns : anns;587 if(v != 0)588 {589 j = readUnsignedShort(v);590 v += 2;591 for(; j > 0; --j)592 {593 v = readAnnotationValues(v + 2,594 c,595 true,596 classVisitor.visitAnnotation(readUTF8(v, c), i != 0));597 }598 }599 }601 // visits the class attributes602 while(cattrs != null)603 {604 attr = cattrs.next;605 cattrs.next = null;606 classVisitor.visitAttribute(cattrs);607 cattrs = attr;608 }610 // calls the visitInnerClass method611 if(w != 0)612 {613 i = readUnsignedShort(w);614 w += 2;615 for(; i > 0; --i)616 {617 classVisitor.visitInnerClass(readUnsignedShort(w) == 0618 ? null619 : readClass(w, c), readUnsignedShort(w + 2) == 0620 ? null621 : readClass(w + 2, c), readUnsignedShort(w + 4) == 0622 ? null623 : readUTF8(w + 4, c),624 readUnsignedShort(w + 6));625 w += 8;626 }627 }629 // visits the fields630 i = readUnsignedShort(u);631 u += 2;632 for(; i > 0; --i)633 {634 access = readUnsignedShort(u);635 name = readUTF8(u + 2, c);636 desc = readUTF8(u + 4, c);637 // visits the field's attributes and looks for a ConstantValue638 // attribute639 int fieldValueItem = 0;640 signature = null;641 anns = 0;642 ianns = 0;643 cattrs = null;645 j = readUnsignedShort(u + 6);646 u += 8;647 for(; j > 0; --j)648 {649 attrName = readUTF8(u, c);650 // tests are sorted in decreasing frequency order651 // (based on frequencies observed on typical classes)652 if(attrName.equals("ConstantValue"))653 {654 fieldValueItem = readUnsignedShort(u + 6);655 }656 else if(attrName.equals("Signature"))657 {658 signature = readUTF8(u + 6, c);659 }660 else if(attrName.equals("Deprecated"))661 {662 access |= Opcodes.ACC_DEPRECATED;663 }664 else if(attrName.equals("Synthetic"))665 {666 access |= Opcodes.ACC_SYNTHETIC;667 }668 else if(attrName.equals("RuntimeVisibleAnnotations"))669 {670 anns = u + 6;671 }672 else if(attrName.equals("RuntimeInvisibleAnnotations"))673 {674 ianns = u + 6;675 }676 else677 {678 attr = readAttribute(attrs,679 attrName,680 u + 6,681 readInt(u + 2),682 c,683 -1,684 null);685 if(attr != null)686 {687 attr.next = cattrs;688 cattrs = attr;689 }690 }691 u += 6 + readInt(u + 2);692 }693 // visits the field694 FieldVisitor fv = classVisitor.visitField(access,695 name,696 desc,697 signature,698 fieldValueItem == 0 ? null : readConst(fieldValueItem, c));699 // visits the field annotations and attributes700 if(fv != null)701 {702 for(j = 1; j >= 0; --j)703 {704 v = j == 0 ? ianns : anns;705 if(v != 0)706 {707 k = readUnsignedShort(v);708 v += 2;709 for(; k > 0; --k)710 {711 v = readAnnotationValues(v + 2,712 c,713 true,714 fv.visitAnnotation(readUTF8(v, c), j != 0));715 }716 }717 }718 while(cattrs != null)719 {720 attr = cattrs.next;721 cattrs.next = null;722 fv.visitAttribute(cattrs);723 cattrs = attr;724 }725 fv.visitEnd();726 }727 }729 // visits the methods730 i = readUnsignedShort(u);731 u += 2;732 for(; i > 0; --i)733 {734 int u0 = u + 6;735 access = readUnsignedShort(u);736 name = readUTF8(u + 2, c);737 desc = readUTF8(u + 4, c);738 signature = null;739 anns = 0;740 ianns = 0;741 int dann = 0;742 int mpanns = 0;743 int impanns = 0;744 cattrs = null;745 v = 0;746 w = 0;748 // looks for Code and Exceptions attributes749 j = readUnsignedShort(u + 6);750 u += 8;751 for(; j > 0; --j)752 {753 attrName = readUTF8(u, c);754 int attrSize = readInt(u + 2);755 u += 6;756 // tests are sorted in decreasing frequency order757 // (based on frequencies observed on typical classes)758 if(attrName.equals("Code"))759 {760 if(!skipCode)761 {762 v = u;763 }764 }765 else if(attrName.equals("Exceptions"))766 {767 w = u;768 }769 else if(attrName.equals("Signature"))770 {771 signature = readUTF8(u, c);772 }773 else if(attrName.equals("Deprecated"))774 {775 access |= Opcodes.ACC_DEPRECATED;776 }777 else if(attrName.equals("RuntimeVisibleAnnotations"))778 {779 anns = u;780 }781 else if(attrName.equals("AnnotationDefault"))782 {783 dann = u;784 }785 else if(attrName.equals("Synthetic"))786 {787 access |= Opcodes.ACC_SYNTHETIC;788 }789 else if(attrName.equals("RuntimeInvisibleAnnotations"))790 {791 ianns = u;792 }793 else if(attrName.equals("RuntimeVisibleParameterAnnotations"))794 {795 mpanns = u;796 }797 else if(attrName.equals("RuntimeInvisibleParameterAnnotations"))798 {799 impanns = u;800 }801 else802 {803 attr = readAttribute(attrs,804 attrName,805 u,806 attrSize,807 c,808 -1,809 null);810 if(attr != null)811 {812 attr.next = cattrs;813 cattrs = attr;814 }815 }816 u += attrSize;817 }818 // reads declared exceptions819 String[] exceptions;820 if(w == 0)821 {822 exceptions = null;823 }824 else825 {826 exceptions = new String[readUnsignedShort(w)];827 w += 2;828 for(j = 0; j < exceptions.length; ++j)829 {830 exceptions[j] = readClass(w, c);831 w += 2;832 }833 }835 // visits the method's code, if any836 MethodVisitor mv = classVisitor.visitMethod(access,837 name,838 desc,839 signature,840 exceptions);842 if(mv != null)843 {844 /*845 * if the returned MethodVisitor is in fact a MethodWriter, it846 * means there is no method adapter between the reader and the847 * writer. If, in addition, the writer's constant pool was848 * copied from this reader (mw.cw.cr == this), and the signature849 * and exceptions of the method have not been changed, then it850 * is possible to skip all visit events and just copy the851 * original code of the method to the writer (the access, name852 * and descriptor can have been changed, this is not important853 * since they are not copied as is from the reader).854 */855 if(mv instanceof MethodWriter)856 {857 MethodWriter mw = (MethodWriter) mv;858 if(mw.cw.cr == this)859 {860 if(signature == mw.signature)861 {862 boolean sameExceptions = false;863 if(exceptions == null)864 {865 sameExceptions = mw.exceptionCount == 0;866 }867 else868 {869 if(exceptions.length == mw.exceptionCount)870 {871 sameExceptions = true;872 for(j = exceptions.length - 1; j >= 0; --j)873 {874 w -= 2;875 if(mw.exceptions[j] != readUnsignedShort(w))876 {877 sameExceptions = false;878 break;879 }880 }881 }882 }883 if(sameExceptions)884 {885 /*886 * we do not copy directly the code into887 * MethodWriter to save a byte array copy888 * operation. The real copy will be done in889 * ClassWriter.toByteArray().890 */891 mw.classReaderOffset = u0;892 mw.classReaderLength = u - u0;893 continue;894 }895 }896 }897 }899 if(dann != 0)900 {901 AnnotationVisitor dv = mv.visitAnnotationDefault();902 readAnnotationValue(dann, c, null, dv);903 if(dv != null)904 {905 dv.visitEnd();906 }907 }908 for(j = 1; j >= 0; --j)909 {910 w = j == 0 ? ianns : anns;911 if(w != 0)912 {913 k = readUnsignedShort(w);914 w += 2;915 for(; k > 0; --k)916 {917 w = readAnnotationValues(w + 2,918 c,919 true,920 mv.visitAnnotation(readUTF8(w, c), j != 0));921 }922 }923 }924 if(mpanns != 0)925 {926 readParameterAnnotations(mpanns, c, true, mv);927 }928 if(impanns != 0)929 {930 readParameterAnnotations(impanns, c, false, mv);931 }932 while(cattrs != null)933 {934 attr = cattrs.next;935 cattrs.next = null;936 mv.visitAttribute(cattrs);937 cattrs = attr;938 }939 }941 if(mv != null && v != 0)942 {943 int maxStack = readUnsignedShort(v);944 int maxLocals = readUnsignedShort(v + 2);945 int codeLength = readInt(v + 4);946 v += 8;948 int codeStart = v;949 int codeEnd = v + codeLength;951 mv.visitCode();953 // 1st phase: finds the labels954 int label;955 Label[] labels = new Label[codeLength + 1];956 while(v < codeEnd)957 {958 int opcode = b[v] & 0xFF;959 switch(ClassWriter.TYPE[opcode])960 {961 case ClassWriter.NOARG_INSN:962 case ClassWriter.IMPLVAR_INSN:963 v += 1;964 break;965 case ClassWriter.LABEL_INSN:966 label = v - codeStart + readShort(v + 1);967 if(labels[label] == null)968 {969 labels[label] = new Label();970 }971 v += 3;972 break;973 case ClassWriter.LABELW_INSN:974 label = v - codeStart + readInt(v + 1);975 if(labels[label] == null)976 {977 labels[label] = new Label();978 }979 v += 5;980 break;981 case ClassWriter.WIDE_INSN:982 opcode = b[v + 1] & 0xFF;983 if(opcode == Opcodes.IINC)984 {985 v += 6;986 }987 else988 {989 v += 4;990 }991 break;992 case ClassWriter.TABL_INSN:993 // skips 0 to 3 padding bytes994 w = v - codeStart;995 v = v + 4 - (w & 3);996 // reads instruction997 label = w + readInt(v);998 if(labels[label] == null)999 {1000 labels[label] = new Label();1001 }1002 j = readInt(v + 8) - readInt(v + 4) + 1;1003 v += 12;1004 for(; j > 0; --j)1005 {1006 label = w + readInt(v);1007 v += 4;1008 if(labels[label] == null)1009 {1010 labels[label] = new Label();1011 }1012 }1013 break;1014 case ClassWriter.LOOK_INSN:1015 // skips 0 to 3 padding bytes1016 w = v - codeStart;1017 v = v + 4 - (w & 3);1018 // reads instruction1019 label = w + readInt(v);1020 if(labels[label] == null)1021 {1022 labels[label] = new Label();1023 }1024 j = readInt(v + 4);1025 v += 8;1026 for(; j > 0; --j)1027 {1028 label = w + readInt(v + 4);1029 v += 8;1030 if(labels[label] == null)1031 {1032 labels[label] = new Label();1033 }1034 }1035 break;1036 case ClassWriter.VAR_INSN:1037 case ClassWriter.SBYTE_INSN:1038 case ClassWriter.LDC_INSN:1039 v += 2;1040 break;1041 case ClassWriter.SHORT_INSN:1042 case ClassWriter.LDCW_INSN:1043 case ClassWriter.FIELDORMETH_INSN:1044 case ClassWriter.TYPE_INSN:1045 case ClassWriter.IINC_INSN:1046 v += 3;1047 break;1048 case ClassWriter.ITFMETH_INSN:1049 v += 5;1050 break;1051 // case MANA_INSN:1052 default:1053 v += 4;1054 break;1055 }1056 }1057 // parses the try catch entries1058 j = readUnsignedShort(v);1059 v += 2;1060 for(; j > 0; --j)1061 {1062 label = readUnsignedShort(v);1063 Label start = labels[label];1064 if(start == null)1065 {1066 labels[label] = start = new Label();1067 }1068 label = readUnsignedShort(v + 2);1069 Label end = labels[label];1070 if(end == null)1071 {1072 labels[label] = end = new Label();1073 }1074 label = readUnsignedShort(v + 4);1075 Label handler = labels[label];1076 if(handler == null)1077 {1078 labels[label] = handler = new Label();1079 }1080 int type = readUnsignedShort(v + 6);1081 if(type == 0)1082 {1083 mv.visitTryCatchBlock(start, end, handler, null);1084 }1085 else1086 {1087 mv.visitTryCatchBlock(start,1088 end,1089 handler,1090 readUTF8(items[type], c));1091 }1092 v += 8;1093 }1094 // parses the local variable, line number tables, and code1095 // attributes1096 int varTable = 0;1097 int varTypeTable = 0;1098 int stackMap = 0;1099 int frameCount = 0;1100 int frameMode = 0;1101 int frameOffset = 0;1102 int frameLocalCount = 0;1103 int frameLocalDiff = 0;1104 int frameStackCount = 0;1105 Object[] frameLocal = null;1106 Object[] frameStack = null;1107 boolean zip = true;1108 cattrs = null;1109 j = readUnsignedShort(v);1110 v += 2;1111 for(; j > 0; --j)1112 {1113 attrName = readUTF8(v, c);1114 if(attrName.equals("LocalVariableTable"))1115 {1116 if(!skipDebug)1117 {1118 varTable = v + 6;1119 k = readUnsignedShort(v + 6);1120 w = v + 8;1121 for(; k > 0; --k)1122 {1123 label = readUnsignedShort(w);1124 if(labels[label] == null)1125 {1126 labels[label] = new Label(true);1127 }1128 label += readUnsignedShort(w + 2);1129 if(labels[label] == null)1130 {1131 labels[label] = new Label(true);1132 }1133 w += 10;1134 }1135 }1136 }1137 else if(attrName.equals("LocalVariableTypeTable"))1138 {1139 varTypeTable = v + 6;1140 }1141 else if(attrName.equals("LineNumberTable"))1142 {1143 if(!skipDebug)1144 {1145 k = readUnsignedShort(v + 6);1146 w = v + 8;1147 for(; k > 0; --k)1148 {1149 label = readUnsignedShort(w);1150 if(labels[label] == null)1151 {1152 labels[label] = new Label(true);1153 }1154 labels[label].line = readUnsignedShort(w + 2);1155 w += 4;1156 }1157 }1158 }1159 else if(attrName.equals("StackMapTable"))1160 {1161 if((flags & SKIP_FRAMES) == 0)1162 {1163 stackMap = v + 8;1164 frameCount = readUnsignedShort(v + 6);1165 }1166 /*1167 * here we do not extract the labels corresponding to1168 * the attribute content. This would require a full1169 * parsing of the attribute, which would need to be1170 * repeated in the second phase (see below). Instead the1171 * content of the attribute is read one frame at a time1172 * (i.e. after a frame has been visited, the next frame1173 * is read), and the labels it contains are also1174 * extracted one frame at a time. Thanks to the ordering1175 * of frames, having only a "one frame lookahead" is not1176 * a problem, i.e. it is not possible to see an offset1177 * smaller than the offset of the current insn and for1178 * which no Label exist.1179 */1180 // TODO true for frame offsets,1181 // but for UNINITIALIZED type offsets?1182 }1183 else if(attrName.equals("StackMap"))1184 {1185 if((flags & SKIP_FRAMES) == 0)1186 {1187 stackMap = v + 8;1188 frameCount = readUnsignedShort(v + 6);1189 zip = false;1190 }1191 /*1192 * IMPORTANT! here we assume that the frames are1193 * ordered, as in the StackMapTable attribute, although1194 * this is not guaranteed by the attribute format.1195 */1196 }1197 else1198 {1199 for(k = 0; k < attrs.length; ++k)1200 {1201 if(attrs[k].type.equals(attrName))1202 {1203 attr = attrs[k].read(this,1204 v + 6,1205 readInt(v + 2),1206 c,1207 codeStart - 8,1208 labels);1209 if(attr != null)1210 {1211 attr.next = cattrs;1212 cattrs = attr;1213 }1214 }1215 }1216 }1217 v += 6 + readInt(v + 2);1218 }1220 // 2nd phase: visits each instruction1221 if(stackMap != 0)1222 {1223 // creates the very first (implicit) frame from the method1224 // descriptor1225 frameLocal = new Object[maxLocals];1226 frameStack = new Object[maxStack];1227 if(unzip)1228 {1229 int local = 0;1230 if((access & Opcodes.ACC_STATIC) == 0)1231 {1232 if(name.equals("<init>"))1233 {1234 frameLocal[local++] = Opcodes.UNINITIALIZED_THIS;1235 }1236 else1237 {1238 frameLocal[local++] = readClass(header + 2, c);1239 }1240 }1241 j = 1;1242 loop:1243 while(true)1244 {1245 k = j;1246 switch(desc.charAt(j++))1247 {1248 case'Z':1249 case'C':1250 case'B':1251 case'S':1252 case'I':1253 frameLocal[local++] = Opcodes.INTEGER;1254 break;1255 case'F':1256 frameLocal[local++] = Opcodes.FLOAT;1257 break;1258 case'J':1259 frameLocal[local++] = Opcodes.LONG;1260 break;1261 case'D':1262 frameLocal[local++] = Opcodes.DOUBLE;1263 break;1264 case'[':1265 while(desc.charAt(j) == '[')1266 {1267 ++j;1268 }1269 if(desc.charAt(j) == 'L')1270 {1271 ++j;1272 while(desc.charAt(j) != ';')1273 {1274 ++j;1275 }1276 }1277 frameLocal[local++] = desc.substring(k, ++j);1278 break;1279 case'L':1280 while(desc.charAt(j) != ';')1281 {1282 ++j;1283 }1284 frameLocal[local++] = desc.substring(k + 1,1285 j++);1286 break;1287 default:1288 break loop;1289 }1290 }1291 frameLocalCount = local;1292 }1293 /*1294 * for the first explicit frame the offset is not1295 * offset_delta + 1 but only offset_delta; setting the1296 * implicit frame offset to -1 allow the use of the1297 * "offset_delta + 1" rule in all cases1298 */1299 frameOffset = -1;1300 }1301 v = codeStart;1302 Label l;1303 while(v < codeEnd)1304 {1305 w = v - codeStart;1307 l = labels[w];1308 if(l != null)1309 {1310 mv.visitLabel(l);1311 if(!skipDebug && l.line > 0)1312 {1313 mv.visitLineNumber(l.line, l);1314 }1315 }1317 while(frameLocal != null1318 && (frameOffset == w || frameOffset == -1))1319 {1320 // if there is a frame for this offset,1321 // makes the visitor visit it,1322 // and reads the next frame if there is one.1323 if(!zip || unzip)1324 {1325 mv.visitFrame(Opcodes.F_NEW,1326 frameLocalCount,1327 frameLocal,1328 frameStackCount,1329 frameStack);1330 }1331 else if(frameOffset != -1)1332 {1333 mv.visitFrame(frameMode,1334 frameLocalDiff,1335 frameLocal,1336 frameStackCount,1337 frameStack);1338 }1340 if(frameCount > 0)1341 {1342 int tag, delta, n;1343 if(zip)1344 {1345 tag = b[stackMap++] & 0xFF;1346 }1347 else1348 {1349 tag = MethodWriter.FULL_FRAME;1350 frameOffset = -1;1351 }1352 frameLocalDiff = 0;1353 if(tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME)1354 {1355 delta = tag;1356 frameMode = Opcodes.F_SAME;1357 frameStackCount = 0;1358 }1359 else if(tag < MethodWriter.RESERVED)1360 {1361 delta = tag1362 - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;1363 stackMap = readFrameType(frameStack,1364 0,1365 stackMap,1366 c,1367 labels);1368 frameMode = Opcodes.F_SAME1;1369 frameStackCount = 1;1370 }1371 else1372 {1373 delta = readUnsignedShort(stackMap);1374 stackMap += 2;1375 if(tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)1376 {1377 stackMap = readFrameType(frameStack,1378 0,1379 stackMap,1380 c,1381 labels);1382 frameMode = Opcodes.F_SAME1;1383 frameStackCount = 1;1384 }1385 else if(tag >= MethodWriter.CHOP_FRAME1386 && tag < MethodWriter.SAME_FRAME_EXTENDED)1387 {1388 frameMode = Opcodes.F_CHOP;1389 frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED1390 - tag;1391 frameLocalCount -= frameLocalDiff;1392 frameStackCount = 0;1393 }1394 else if(tag == MethodWriter.SAME_FRAME_EXTENDED)1395 {1396 frameMode = Opcodes.F_SAME;1397 frameStackCount = 0;1398 }1399 else if(tag < MethodWriter.FULL_FRAME)1400 {1401 j = unzip ? frameLocalCount : 0;1402 for(k = tag1403 - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--)1404 {1405 stackMap = readFrameType(frameLocal,1406 j++,1407 stackMap,1408 c,1409 labels);1410 }1411 frameMode = Opcodes.F_APPEND;1412 frameLocalDiff = tag1413 - MethodWriter.SAME_FRAME_EXTENDED;1414 frameLocalCount += frameLocalDiff;1415 frameStackCount = 0;1416 }1417 else1418 { // if (tag == FULL_FRAME) {1419 frameMode = Opcodes.F_FULL;1420 n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap);1421 stackMap += 2;1422 for(j = 0; n > 0; n--)1423 {1424 stackMap = readFrameType(frameLocal,1425 j++,1426 stackMap,1427 c,1428 labels);1429 }1430 n = frameStackCount = readUnsignedShort(stackMap);1431 stackMap += 2;1432 for(j = 0; n > 0; n--)1433 {1434 stackMap = readFrameType(frameStack,1435 j++,1436 stackMap,1437 c,1438 labels);1439 }1440 }1441 }1442 frameOffset += delta + 1;1443 if(labels[frameOffset] == null)1444 {1445 labels[frameOffset] = new Label();1446 }1448 --frameCount;1449 }1450 else1451 {1452 frameLocal = null;1453 }1454 }1456 int opcode = b[v] & 0xFF;1457 switch(ClassWriter.TYPE[opcode])1458 {1459 case ClassWriter.NOARG_INSN:1460 mv.visitInsn(opcode);1461 v += 1;1462 break;1463 case ClassWriter.IMPLVAR_INSN:1464 if(opcode > Opcodes.ISTORE)1465 {1466 opcode -= 59; // ISTORE_01467 mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2),1468 opcode & 0x3);1469 }1470 else1471 {1472 opcode -= 26; // ILOAD_01473 mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2),1474 opcode & 0x3);1475 }1476 v += 1;1477 break;1478 case ClassWriter.LABEL_INSN:1479 mv.visitJumpInsn(opcode, labels[w1480 + readShort(v + 1)]);1481 v += 3;1482 break;1483 case ClassWriter.LABELW_INSN:1484 mv.visitJumpInsn(opcode - 33, labels[w1485 + readInt(v + 1)]);1486 v += 5;1487 break;1488 case ClassWriter.WIDE_INSN:1489 opcode = b[v + 1] & 0xFF;1490 if(opcode == Opcodes.IINC)1491 {1492 mv.visitIincInsn(readUnsignedShort(v + 2),1493 readShort(v + 4));1494 v += 6;1495 }1496 else1497 {1498 mv.visitVarInsn(opcode,1499 readUnsignedShort(v + 2));1500 v += 4;1501 }1502 break;1503 case ClassWriter.TABL_INSN:1504 // skips 0 to 3 padding bytes1505 v = v + 4 - (w & 3);1506 // reads instruction1507 label = w + readInt(v);1508 int min = readInt(v + 4);1509 int max = readInt(v + 8);1510 v += 12;1511 Label[] table = new Label[max - min + 1];1512 for(j = 0; j < table.length; ++j)1513 {1514 table[j] = labels[w + readInt(v)];1515 v += 4;1516 }1517 mv.visitTableSwitchInsn(min,1518 max,1519 labels[label],1520 table);1521 break;1522 case ClassWriter.LOOK_INSN:1523 // skips 0 to 3 padding bytes1524 v = v + 4 - (w & 3);1525 // reads instruction1526 label = w + readInt(v);1527 j = readInt(v + 4);1528 v += 8;1529 int[] keys = new int[j];1530 Label[] values = new Label[j];1531 for(j = 0; j < keys.length; ++j)1532 {1533 keys[j] = readInt(v);1534 values[j] = labels[w + readInt(v + 4)];1535 v += 8;1536 }1537 mv.visitLookupSwitchInsn(labels[label],1538 keys,1539 values);1540 break;1541 case ClassWriter.VAR_INSN:1542 mv.visitVarInsn(opcode, b[v + 1] & 0xFF);1543 v += 2;1544 break;1545 case ClassWriter.SBYTE_INSN:1546 mv.visitIntInsn(opcode, b[v + 1]);1547 v += 2;1548 break;1549 case ClassWriter.SHORT_INSN:1550 mv.visitIntInsn(opcode, readShort(v + 1));1551 v += 3;1552 break;1553 case ClassWriter.LDC_INSN:1554 mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));1555 v += 2;1556 break;1557 case ClassWriter.LDCW_INSN:1558 mv.visitLdcInsn(readConst(readUnsignedShort(v + 1),1559 c));1560 v += 3;1561 break;1562 case ClassWriter.FIELDORMETH_INSN:1563 case ClassWriter.ITFMETH_INSN:1564 int cpIndex = items[readUnsignedShort(v + 1)];1565 String iowner = readClass(cpIndex, c);1566 cpIndex = items[readUnsignedShort(cpIndex + 2)];1567 String iname = readUTF8(cpIndex, c);1568 String idesc = readUTF8(cpIndex + 2, c);1569 if(opcode < Opcodes.INVOKEVIRTUAL)1570 {1571 mv.visitFieldInsn(opcode, iowner, iname, idesc);1572 }1573 else1574 {1575 mv.visitMethodInsn(opcode, iowner, iname, idesc);1576 }1577 if(opcode == Opcodes.INVOKEINTERFACE)1578 {1579 v += 5;1580 }1581 else1582 {1583 v += 3;1584 }1585 break;1586 case ClassWriter.TYPE_INSN:1587 mv.visitTypeInsn(opcode, readClass(v + 1, c));1588 v += 3;1589 break;1590 case ClassWriter.IINC_INSN:1591 mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);1592 v += 3;1593 break;1594 // case MANA_INSN:1595 default:1596 mv.visitMultiANewArrayInsn(readClass(v + 1, c),1597 b[v + 3] & 0xFF);1598 v += 4;1599 break;1600 }1601 }1602 l = labels[codeEnd - codeStart];1603 if(l != null)1604 {1605 mv.visitLabel(l);1606 }1607 // visits the local variable tables1608 if(!skipDebug && varTable != 0)1609 {1610 int[] typeTable = null;1611 if(varTypeTable != 0)1612 {1613 k = readUnsignedShort(varTypeTable) * 3;1614 w = varTypeTable + 2;1615 typeTable = new int[k];1616 while(k > 0)1617 {1618 typeTable[--k] = w + 6; // signature1619 typeTable[--k] = readUnsignedShort(w + 8); // index1620 typeTable[--k] = readUnsignedShort(w); // start1621 w += 10;1622 }1623 }1624 k = readUnsignedShort(varTable);1625 w = varTable + 2;1626 for(; k > 0; --k)1627 {1628 int start = readUnsignedShort(w);1629 int length = readUnsignedShort(w + 2);1630 int index = readUnsignedShort(w + 8);1631 String vsignature = null;1632 if(typeTable != null)1633 {1634 for(int a = 0; a < typeTable.length; a += 3)1635 {1636 if(typeTable[a] == start1637 && typeTable[a + 1] == index)1638 {1639 vsignature = readUTF8(typeTable[a + 2], c);1640 break;1641 }1642 }1643 }1644 mv.visitLocalVariable(readUTF8(w + 4, c),1645 readUTF8(w + 6, c),1646 vsignature,1647 labels[start],1648 labels[start + length],1649 index);1650 w += 10;1651 }1652 }1653 // visits the other attributes1654 while(cattrs != null)1655 {1656 attr = cattrs.next;1657 cattrs.next = null;1658 mv.visitAttribute(cattrs);1659 cattrs = attr;1660 }1661 // visits the max stack and max locals values1662 mv.visitMaxs(maxStack, maxLocals);1663 }1665 if(mv != null)1666 {1667 mv.visitEnd();1668 }1669 }1671 // visits the end of the class1672 classVisitor.visitEnd();1673 }1675 /**1676 * Reads parameter annotations and makes the given visitor visit them.1677 *1678 * @param v start offset in {@link #b b} of the annotations to be read.1679 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},1680 * {@link #readClass(int,char[]) readClass} or1681 * {@link #readConst readConst}.1682 * @param visible <tt>true</tt> if the annotations to be read are visible1683 * at runtime.1684 * @param mv the visitor that must visit the annotations.1685 */1686 private void readParameterAnnotations(1687 int v,1688 final char[] buf,1689 final boolean visible,1690 final MethodVisitor mv){1691 int n = b[v++] & 0xFF;1692 for(int i = 0; i < n; ++i)1693 {1694 int j = readUnsignedShort(v);1695 v += 2;1696 for(; j > 0; --j)1697 {1698 v = readAnnotationValues(v + 2,1699 buf,1700 true,1701 mv.visitParameterAnnotation(i,1702 readUTF8(v, buf),1703 visible));1704 }1705 }1706 }1708 /**1709 * Reads the values of an annotation and makes the given visitor visit them.1710 *1711 * @param v the start offset in {@link #b b} of the values to be read1712 * (including the unsigned short that gives the number of values).1713 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},1714 * {@link #readClass(int,char[]) readClass} or1715 * {@link #readConst readConst}.1716 * @param named if the annotation values are named or not.1717 * @param av the visitor that must visit the values.1718 * @return the end offset of the annotation values.1719 */1720 private int readAnnotationValues(1721 int v,1722 final char[] buf,1723 final boolean named,1724 final AnnotationVisitor av){1725 int i = readUnsignedShort(v);1726 v += 2;1727 if(named)1728 {1729 for(; i > 0; --i)1730 {1731 v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av);1732 }1733 }1734 else1735 {1736 for(; i > 0; --i)1737 {1738 v = readAnnotationValue(v, buf, null, av);1739 }1740 }1741 if(av != null)1742 {1743 av.visitEnd();1744 }1745 return v;1746 }1748 /**1749 * Reads a value of an annotation and makes the given visitor visit it.1750 *1751 * @param v the start offset in {@link #b b} of the value to be read (<i>not1752 * including the value name constant pool index</i>).1753 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},1754 * {@link #readClass(int,char[]) readClass} or1755 * {@link #readConst readConst}.1756 * @param name the name of the value to be read.1757 * @param av the visitor that must visit the value.1758 * @return the end offset of the annotation value.1759 */1760 private int readAnnotationValue(1761 int v,1762 final char[] buf,1763 final String name,1764 final AnnotationVisitor av){1765 int i;1766 if(av == null)1767 {1768 switch(b[v] & 0xFF)1769 {1770 case'e': // enum_const_value1771 return v + 5;1772 case'@': // annotation_value1773 return readAnnotationValues(v + 3, buf, true, null);1774 case'[': // array_value1775 return readAnnotationValues(v + 1, buf, false, null);1776 default:1777 return v + 3;1778 }1779 }1780 switch(b[v++] & 0xFF)1781 {1782 case'I': // pointer to CONSTANT_Integer1783 case'J': // pointer to CONSTANT_Long1784 case'F': // pointer to CONSTANT_Float1785 case'D': // pointer to CONSTANT_Double1786 av.visit(name, readConst(readUnsignedShort(v), buf));1787 v += 2;1788 break;1789 case'B': // pointer to CONSTANT_Byte1790 av.visit(name,1791 new Byte((byte) readInt(items[readUnsignedShort(v)])));1792 v += 2;1793 break;1794 case'Z': // pointer to CONSTANT_Boolean1795 av.visit(name, readInt(items[readUnsignedShort(v)]) == 01796 ? Boolean.FALSE1797 : Boolean.TRUE);1798 v += 2;1799 break;1800 case'S': // pointer to CONSTANT_Short1801 av.visit(name,1802 new Short((short) readInt(items[readUnsignedShort(v)])));1803 v += 2;1804 break;1805 case'C': // pointer to CONSTANT_Char1806 av.visit(name,1807 new Character((char) readInt(items[readUnsignedShort(v)])));1808 v += 2;1809 break;1810 case's': // pointer to CONSTANT_Utf81811 av.visit(name, readUTF8(v, buf));1812 v += 2;1813 break;1814 case'e': // enum_const_value1815 av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));1816 v += 4;1817 break;1818 case'c': // class_info1819 av.visit(name, Type.getType(readUTF8(v, buf)));1820 v += 2;1821 break;1822 case'@': // annotation_value1823 v = readAnnotationValues(v + 2,1824 buf,1825 true,1826 av.visitAnnotation(name, readUTF8(v, buf)));1827 break;1828 case'[': // array_value1829 int size = readUnsignedShort(v);1830 v += 2;1831 if(size == 0)1832 {1833 return readAnnotationValues(v - 2,1834 buf,1835 false,1836 av.visitArray(name));1837 }1838 switch(this.b[v++] & 0xFF)1839 {1840 case'B':1841 byte[] bv = new byte[size];1842 for(i = 0; i < size; i++)1843 {1844 bv[i] = (byte) readInt(items[readUnsignedShort(v)]);1845 v += 3;1846 }1847 av.visit(name, bv);1848 --v;1849 break;1850 case'Z':1851 boolean[] zv = new boolean[size];1852 for(i = 0; i < size; i++)1853 {1854 zv[i] = readInt(items[readUnsignedShort(v)]) != 0;1855 v += 3;1856 }1857 av.visit(name, zv);1858 --v;1859 break;1860 case'S':1861 short[] sv = new short[size];1862 for(i = 0; i < size; i++)1863 {1864 sv[i] = (short) readInt(items[readUnsignedShort(v)]);1865 v += 3;1866 }1867 av.visit(name, sv);1868 --v;1869 break;1870 case'C':1871 char[] cv = new char[size];1872 for(i = 0; i < size; i++)1873 {1874 cv[i] = (char) readInt(items[readUnsignedShort(v)]);1875 v += 3;1876 }1877 av.visit(name, cv);1878 --v;1879 break;1880 case'I':1881 int[] iv = new int[size];1882 for(i = 0; i < size; i++)1883 {1884 iv[i] = readInt(items[readUnsignedShort(v)]);1885 v += 3;1886 }1887 av.visit(name, iv);1888 --v;1889 break;1890 case'J':1891 long[] lv = new long[size];1892 for(i = 0; i < size; i++)1893 {1894 lv[i] = readLong(items[readUnsignedShort(v)]);1895 v += 3;1896 }1897 av.visit(name, lv);1898 --v;1899 break;1900 case'F':1901 float[] fv = new float[size];1902 for(i = 0; i < size; i++)1903 {1904 fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)]));1905 v += 3;1906 }1907 av.visit(name, fv);1908 --v;1909 break;1910 case'D':1911 double[] dv = new double[size];1912 for(i = 0; i < size; i++)1913 {1914 dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)]));1915 v += 3;1916 }1917 av.visit(name, dv);1918 --v;1919 break;1920 default:1921 v = readAnnotationValues(v - 3,1922 buf,1923 false,1924 av.visitArray(name));1925 }1926 }1927 return v;1928 }1930 private int readFrameType(1931 final Object[] frame,1932 final int index,1933 int v,1934 final char[] buf,1935 final Label[] labels){1936 int type = b[v++] & 0xFF;1937 switch(type)1938 {1939 case 0:1940 frame[index] = Opcodes.TOP;1941 break;1942 case 1:1943 frame[index] = Opcodes.INTEGER;1944 break;1945 case 2:1946 frame[index] = Opcodes.FLOAT;1947 break;1948 case 3:1949 frame[index] = Opcodes.DOUBLE;1950 break;1951 case 4:1952 frame[index] = Opcodes.LONG;1953 break;1954 case 5:1955 frame[index] = Opcodes.NULL;1956 break;1957 case 6:1958 frame[index] = Opcodes.UNINITIALIZED_THIS;1959 break;1960 case 7: // Object1961 frame[index] = readClass(v, buf);1962 v += 2;1963 break;1964 default: // Uninitialized1965 int offset = readUnsignedShort(v);1966 if(labels[offset] == null)1967 {1968 labels[offset] = new Label();1969 }1970 frame[index] = labels[offset];1971 v += 2;1972 }1973 return v;1974 }1976 /**1977 * Reads an attribute in {@link #b b}.1978 *1979 * @param attrs prototypes of the attributes that must be parsed during the1980 * visit of the class. Any attribute whose type is not equal to the1981 * type of one the prototypes is ignored (i.e. an empty1982 * {@link Attribute} instance is returned).1983 * @param type the type of the attribute.1984 * @param off index of the first byte of the attribute's content in1985 * {@link #b b}. The 6 attribute header bytes, containing the type1986 * and the length of the attribute, are not taken into account here1987 * (they have already been read).1988 * @param len the length of the attribute's content.1989 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},1990 * {@link #readClass(int,char[]) readClass} or1991 * {@link #readConst readConst}.1992 * @param codeOff index of the first byte of code's attribute content in1993 * {@link #b b}, or -1 if the attribute to be read is not a code1994 * attribute. The 6 attribute header bytes, containing the type and1995 * the length of the attribute, are not taken into account here.1996 * @param labels the labels of the method's code, or <tt>null</tt> if the1997 * attribute to be read is not a code attribute.1998 * @return the attribute that has been read, or <tt>null</tt> to skip this1999 * attribute.2000 */2001 private Attribute readAttribute(2002 final Attribute[] attrs,2003 final String type,2004 final int off,2005 final int len,2006 final char[] buf,2007 final int codeOff,2008 final Label[] labels){2009 for(int i = 0; i < attrs.length; ++i)2010 {2011 if(attrs[i].type.equals(type))2012 {2013 return attrs[i].read(this, off, len, buf, codeOff, labels);2014 }2015 }2016 return new Attribute(type).read(this, off, len, null, -1, null);2017 }2019 // ------------------------------------------------------------------------2020 // Utility methods: low level parsing2021 // ------------------------------------------------------------------------2023 /**2024 * Returns the start index of the constant pool item in {@link #b b}, plus2025 * one. <i>This method is intended for {@link Attribute} sub classes, and is2026 * normally not needed by class generators or adapters.</i>2027 *2028 * @param item the index a constant pool item.2029 * @return the start index of the constant pool item in {@link #b b}, plus2030 * one.2031 */2032 public int getItem(final int item){2033 return items[item];2034 }2036 /**2037 * Reads a byte value in {@link #b b}. <i>This method is intended for2038 * {@link Attribute} sub classes, and is normally not needed by class2039 * generators or adapters.</i>2040 *2041 * @param index the start index of the value to be read in {@link #b b}.2042 * @return the read value.2043 */2044 public int readByte(final int index){2045 return b[index] & 0xFF;2046 }2048 /**2049 * Reads an unsigned short value in {@link #b b}. <i>This method is2050 * intended for {@link Attribute} sub classes, and is normally not needed by2051 * class generators or adapters.</i>2052 *2053 * @param index the start index of the value to be read in {@link #b b}.2054 * @return the read value.2055 */2056 public int readUnsignedShort(final int index){2057 byte[] b = this.b;2058 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);2059 }2061 /**2062 * Reads a signed short value in {@link #b b}. <i>This method is intended2063 * for {@link Attribute} sub classes, and is normally not needed by class2064 * generators or adapters.</i>2065 *2066 * @param index the start index of the value to be read in {@link #b b}.2067 * @return the read value.2068 */2069 public short readShort(final int index){2070 byte[] b = this.b;2071 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));2072 }2074 /**2075 * Reads a signed int value in {@link #b b}. <i>This method is intended for2076 * {@link Attribute} sub classes, and is normally not needed by class2077 * generators or adapters.</i>2078 *2079 * @param index the start index of the value to be read in {@link #b b}.2080 * @return the read value.2081 */2082 public int readInt(final int index){2083 byte[] b = this.b;2084 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)2085 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);2086 }2088 /**2089 * Reads a signed long value in {@link #b b}. <i>This method is intended2090 * for {@link Attribute} sub classes, and is normally not needed by class2091 * generators or adapters.</i>2092 *2093 * @param index the start index of the value to be read in {@link #b b}.2094 * @return the read value.2095 */2096 public long readLong(final int index){2097 long l1 = readInt(index);2098 long l0 = readInt(index + 4) & 0xFFFFFFFFL;2099 return (l1 << 32) | l0;2100 }2102 /**2103 * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method2104 * is intended for {@link Attribute} sub classes, and is normally not needed2105 * by class generators or adapters.</i>2106 *2107 * @param index the start index of an unsigned short value in {@link #b b},2108 * whose value is the index of an UTF8 constant pool item.2109 * @param buf buffer to be used to read the item. This buffer must be2110 * sufficiently large. It is not automatically resized.2111 * @return the String corresponding to the specified UTF8 item.2112 */2113 public String readUTF8(int index, final char[] buf){2114 int item = readUnsignedShort(index);2115 String s = strings[item];2116 if(s != null)2117 {2118 return s;2119 }2120 index = items[item];2121 return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf);2122 }2124 /**2125 * Reads UTF8 string in {@link #b b}.2126 *2127 * @param index start offset of the UTF8 string to be read.2128 * @param utfLen length of the UTF8 string to be read.2129 * @param buf buffer to be used to read the string. This buffer must be2130 * sufficiently large. It is not automatically resized.2131 * @return the String corresponding to the specified UTF8 string.2132 */2133 private String readUTF(int index, final int utfLen, final char[] buf){2134 int endIndex = index + utfLen;2135 byte[] b = this.b;2136 int strLen = 0;2137 int c, d, e;2138 while(index < endIndex)2139 {2140 c = b[index++] & 0xFF;2141 switch(c >> 4)2142 {2143 case 0:2144 case 1:2145 case 2:2146 case 3:2147 case 4:2148 case 5:2149 case 6:2150 case 7:2151 // 0xxxxxxx2152 buf[strLen++] = (char) c;2153 break;2154 case 12:2155 case 13:2156 // 110x xxxx 10xx xxxx2157 d = b[index++];2158 buf[strLen++] = (char) (((c & 0x1F) << 6) | (d & 0x3F));2159 break;2160 default:2161 // 1110 xxxx 10xx xxxx 10xx xxxx2162 d = b[index++];2163 e = b[index++];2164 buf[strLen++] = (char) (((c & 0x0F) << 12)2165 | ((d & 0x3F) << 6) | (e & 0x3F));2166 break;2167 }2168 }2169 return new String(buf, 0, strLen);2170 }2172 /**2173 * Reads a class constant pool item in {@link #b b}. <i>This method is2174 * intended for {@link Attribute} sub classes, and is normally not needed by2175 * class generators or adapters.</i>2176 *2177 * @param index the start index of an unsigned short value in {@link #b b},2178 * whose value is the index of a class constant pool item.2179 * @param buf buffer to be used to read the item. This buffer must be2180 * sufficiently large. It is not automatically resized.2181 * @return the String corresponding to the specified class item.2182 */2183 public String readClass(final int index, final char[] buf){2184 // computes the start index of the CONSTANT_Class item in b2185 // and reads the CONSTANT_Utf8 item designated by2186 // the first two bytes of this CONSTANT_Class item2187 return readUTF8(items[readUnsignedShort(index)], buf);2188 }2190 /**2191 * Reads a numeric or string constant pool item in {@link #b b}. <i>This2192 * method is intended for {@link Attribute} sub classes, and is normally not2193 * needed by class generators or adapters.</i>2194 *2195 * @param item the index of a constant pool item.2196 * @param buf buffer to be used to read the item. This buffer must be2197 * sufficiently large. It is not automatically resized.2198 * @return the {@link Integer}, {@link Float}, {@link Long},2199 * {@link Double}, {@link String} or {@link Type} corresponding to2200 * the given constant pool item.2201 */2202 public Object readConst(final int item, final char[] buf){2203 int index = items[item];2204 switch(b[index - 1])2205 {2206 case ClassWriter.INT:2207 return new Integer(readInt(index));2208 case ClassWriter.FLOAT:2209 return new Float(Float.intBitsToFloat(readInt(index)));2210 case ClassWriter.LONG:2211 return new Long(readLong(index));2212 case ClassWriter.DOUBLE:2213 return new Double(Double.longBitsToDouble(readLong(index)));2214 case ClassWriter.CLASS:2215 String s = readUTF8(index, buf);2216 return s.charAt(0) == '['2217 ? Type.getType(s)2218 : Type.getObjectType(s);2219 // case ClassWriter.STR:2220 default:2221 return readUTF8(index, buf);2222 }2223 }2224 }