Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
ASM: a very small and fast Java bytecode manipulation framework Copyright (c) 2000-2007 INRIA, France Telecom All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  package org.objectweb.asm;
  
A Java class parser to make a ClassVisitor visit an existing class. This class parses a byte array conforming to the Java class file format and calls the appropriate visit methods of a given class visitor for each field, method and bytecode instruction encountered.

Author(s):
Eric Bruneton
Eugene Kuleshov
  
  public class ClassReader {

    
True to enable signatures support.
  
      static final boolean SIGNATURES = true;
    
    
True to enable annotations support.
  
      static final boolean ANNOTATIONS = true;
    
    
True to enable stack map frames support.
  
      static final boolean FRAMES = true;
    
    
True to enable bytecode writing support.
  
      static final boolean WRITER = true;
    
    
True to enable JSR_W and GOTO_W support.
  
      static final boolean RESIZE = true;
    
    
Flag to skip method code. If this class is set CODE attribute won't be visited. This can be used, for example, to retrieve annotations for methods and method parameters.
  
      public static final int SKIP_CODE = 1;

    
Flag to skip the debug information in the class. If this flag is set the debug information of the class is not visited, i.e. the visitLocalVariable and visitLineNumber methods will not be called.
  
      public static final int SKIP_DEBUG = 2;

    
Flag to skip the stack map frames in the class. If this flag is set the stack map frames of the class is not visited, i.e. the visitFrame method will not be called. This flag is useful when the ClassWriter.COMPUTE_FRAMES option is used: it avoids visiting frames that will be ignored and recomputed from scratch in the class writer.
  
      public static final int SKIP_FRAMES = 4;

    
Flag to expand the stack map frames. By default stack map frames are visited in their original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed" for the other classes). If this flag is set, stack map frames are always visited in expanded format (this option adds a decompression/recompression step in ClassReader and ClassWriter which degrades performances quite a lot).
 
     public static final int EXPAND_FRAMES = 8;

    
The class to be parsed. The content of this array must not be modified. This field is intended for Attribute sub classes, and is normally not needed by class generators or adapters.
 
     public final byte[] b;

    
The start index of each constant pool item in b, plus one. The one byte offset skips the constant pool item tag that indicates its type.
 
     private final int[] items;

    
The String objects corresponding to the CONSTANT_Utf8 items. This cache avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, which GREATLY improves performances (by a factor 2 to 3). This caching strategy could be extended to all constant pool items, but its benefit would not be so great for these items (because they are much less expensive to parse than CONSTANT_Utf8 items).
 
     private final String[] strings;

    
Maximum length of the strings contained in the constant pool of the class.
 
     private final int maxStringLength;

    
Start index of the class header information (access, name...) in b.
 
     public final int header;
 
     // ------------------------------------------------------------------------
     // Constructors
     // ------------------------------------------------------------------------
 
    
Constructs a new ClassReader object.

Parameters:
b the bytecode of the class to be read.
 
     public ClassReader(final byte[] b) {
         this(b, 0, b.length);
     }

    
Constructs a new ClassReader object.

Parameters:
b the bytecode of the class to be read.
off the start offset of the class data.
len the length of the class data.
 
     public ClassReader(final byte[] bfinal int offfinal int len) {
         this. = b;
         // parses the constant pool
          = new int[readUnsignedShort(off + 8)];
         int n = .;
          = new String[n];
         int max = 0;
         int index = off + 10;
         for (int i = 1; i < n; ++i) {
             [i] = index + 1;
             int size;
             switch (b[index]) {
                 case .:
                 case .:
                 case .:
                 case .:
                 case .:
                 case .:
                     size = 5;
                     break;
                 case .:
                 case .:
                     size = 9;
                     ++i;
                     break;
                 case .:
                     size = 3 + readUnsignedShort(index + 1);
                     if (size > max) {
                         max = size;
                     }
                     break;
                 // case ClassWriter.CLASS:
                 // case ClassWriter.STR:
                 default:
                     size = 3;
                     break;
             }
             index += size;
         }
          = max;
         // the class header information starts just after the constant pool
          = index;
     }

    
Returns the class's access flags (see Opcodes). This value may not reflect Deprecated and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes.

 
     public int getAccess() {
         return readUnsignedShort();
     }

    
Returns the internal name of the class (see getInternalName).

 
     public String getClassName() {
         return readClass( + 2, new char[]);
     }

    
Returns the internal of name of the super class (see getInternalName). For interfaces, the super class is java.lang.Object.

 
     public String getSuperName() {
         int n = [readUnsignedShort( + 4)];
         return n == 0 ? null : readUTF8(nnew char[]);
     }

    
Returns the internal names of the class's interfaces (see getInternalName).

Returns:
the array of internal names for all implemented interfaces or null.
See also:
ClassVisitor.visit(int,int,java.lang.String,java.lang.String,java.lang.String,java.lang.String[])
 
     public String[] getInterfaces() {
         int index =  + 6;
         int n = readUnsignedShort(index);
         String[] interfaces = new String[n];
         if (n > 0) {
             char[] buf = new char[];
             for (int i = 0; i < n; ++i) {
                 index += 2;
                 interfaces[i] = readClass(indexbuf);
             }
         }
         return interfaces;
     }

    
Copies the constant pool data into the given ClassWriter. Should be called before the accept(org.objectweb.asm.ClassVisitor,int) method.

Parameters:
classWriter the ClassWriter to copy constant pool into.
 
     void copyPool(final ClassWriter classWriter) {
         char[] buf = new char[];
         int ll = .;
         Item[] items2 = new Item[ll];
         for (int i = 1; i < lli++) {
             int index = [i];
             int tag = [index - 1];
             Item item = new Item(i);
             int nameType;
             switch (tag) {
                 case .:
                 case .:
                 case .:
                     nameType = [readUnsignedShort(index + 2)];
                     item.set(tag,
                             readClass(indexbuf),
                             readUTF8(nameTypebuf),
                             readUTF8(nameType + 2, buf));
                     break;
 
                 case .:
                     item.set(readInt(index));
                     break;
 
                 case .:
                     item.set(Float.intBitsToFloat(readInt(index)));
                     break;
 
                 case .:
                     item.set(tag,
                             readUTF8(indexbuf),
                             readUTF8(index + 2, buf),
                             null);
                     break;
 
                 case .:
                     item.set(readLong(index));
                     ++i;
                     break;
 
                 case .:
                     item.set(Double.longBitsToDouble(readLong(index)));
                     ++i;
                     break;
 
                 case .: {
                     String s = [i];
                     if (s == null) {
                         index = [i];
                         s = [i] = readUTF(index + 2,
                                 readUnsignedShort(index),
                                 buf);
                     }
                     item.set(tagsnullnull);
                 }
                     break;
 
                 // case ClassWriter.STR:
                 // case ClassWriter.CLASS:
                 default:
                     item.set(tagreadUTF8(indexbuf), nullnull);
                     break;
             }
 
             int index2 = item.hashCode % items2.length;
             item.next = items2[index2];
             items2[index2] = item;
         }
 
         int off = [1] - 1;
         classWriter.pool.putByteArray(off - off);
         classWriter.items = items2;
         classWriter.threshold = (int) (0.75d * ll);
         classWriter.index = ll;
     }

    
Constructs a new ClassReader object.

Parameters:
is an input stream from which to read the class.
Throws:
java.io.IOException if a problem occurs during reading.
 
     public ClassReader(final InputStream isthrows IOException {
         this(readClass(is));
     }

    
Constructs a new ClassReader object.

Parameters:
name the fully qualified name of the class to be read.
Throws:
java.io.IOException if an exception occurs during reading.
 
     public ClassReader(final String namethrows IOException {
         this(ClassLoader.getSystemResourceAsStream(name.replace('.''/')
                 + ".class"));
     }

    
Reads the bytecode of a class.

Parameters:
is an input stream from which to read the class.
Returns:
the bytecode read from the given input stream.
Throws:
java.io.IOException if a problem occurs during reading.
 
     private static byte[] readClass(final InputStream isthrows IOException {
         if (is == null) {
             throw new IOException("Class not found");
         }
         byte[] b = new byte[is.available()];
         int len = 0;
         while (true) {
             int n = is.read(blenb.length - len);
             if (n == -1) {
                 if (len < b.length) {
                     byte[] c = new byte[len];
                     System.arraycopy(b, 0, c, 0, len);
                     b = c;
                 }
                 return b;
             }
             len += n;
             if (len == b.length) {
                 byte[] c = new byte[b.length + 1000];
                 System.arraycopy(b, 0, c, 0, len);
                 b = c;
             }
         }
     }
 
     // ------------------------------------------------------------------------
     // Public methods
     // ------------------------------------------------------------------------
 
    
Makes the given visitor visit the Java class of this ClassReader. This class is the one specified in the constructor (see ClassReader).

Parameters:
classVisitor the visitor that must visit this class.
flags option flags that can be used to modify the default behavior of this class. See SKIP_DEBUG, EXPAND_FRAMES, SKIP_FRAMES, SKIP_CODE.
 
     public void accept(final ClassVisitor classVisitorfinal int flags) {
         accept(classVisitornew Attribute[0], flags);
     }

    
Makes the given visitor visit the Java class of this ClassReader. This class is the one specified in the constructor (see ClassReader).

Parameters:
classVisitor the visitor that must visit this class.
attrs prototypes of the attributes that must be parsed during the visit of the class. Any attribute whose type is not equal to the type of one the prototypes will not be parsed: its byte array value will be passed unchanged to the ClassWriter. This may corrupt it if this value contains references to the constant pool, or has syntactic or semantic links with a class element that has been transformed by a class adapter between the reader and the writer.
flags option flags that can be used to modify the default behavior of this class. See SKIP_DEBUG, EXPAND_FRAMES, SKIP_FRAMES, SKIP_CODE.
 
     public void accept(
         final ClassVisitor classVisitor,
         final Attribute[] attrs,
         final int flags)
     {
         byte[] b = this.// the bytecode array
         char[] c = new char[]; // buffer used to read strings
         int ijk// loop variables
         int uvw// indexes in b
         Attribute attr;
 
         int access;
         String name;
         String desc;
         String attrName;
         String signature;
         int anns = 0;
         int ianns = 0;
         Attribute cattrs = null;
 
         // visits the header
         u = ;
         access = readUnsignedShort(u);
         name = readClass(u + 2, c);
         v = [readUnsignedShort(u + 4)];
         String superClassName = v == 0 ? null : readUTF8(vc);
         String[] implementedItfs = new String[readUnsignedShort(u + 6)];
         w = 0;
         u += 8;
         for (i = 0; i < implementedItfs.length; ++i) {
             implementedItfs[i] = readClass(uc);
             u += 2;
         }
 
         boolean skipCode = (flags & ) != 0;
         boolean skipDebug = (flags & ) != 0;
         boolean unzip = (flags & ) != 0;
 
         // skips fields and methods
         v = u;
         i = readUnsignedShort(v);
         v += 2;
         for (; i > 0; --i) {
             j = readUnsignedShort(v + 6);
             v += 8;
             for (; j > 0; --j) {
                 v += 6 + readInt(v + 2);
             }
         }
         i = readUnsignedShort(v);
         v += 2;
         for (; i > 0; --i) {
             j = readUnsignedShort(v + 6);
             v += 8;
             for (; j > 0; --j) {
                 v += 6 + readInt(v + 2);
             }
         }
         // reads the class's attributes
         signature = null;
         String sourceFile = null;
         String sourceDebug = null;
         String enclosingOwner = null;
         String enclosingName = null;
         String enclosingDesc = null;
 
         i = readUnsignedShort(v);
         v += 2;
         for (; i > 0; --i) {
             attrName = readUTF8(vc);
             // tests are sorted in decreasing frequency order
             // (based on frequencies observed on typical classes)
             if ("SourceFile".equals(attrName)) {
                 sourceFile = readUTF8(v + 6, c);
             } else if ("InnerClasses".equals(attrName)) {
                 w = v + 6;
             } else if ("EnclosingMethod".equals(attrName)) {
                 enclosingOwner = readClass(v + 6, c);
                 int item = readUnsignedShort(v + 8);
                 if (item != 0) {
                     enclosingName = readUTF8([item], c);
                     enclosingDesc = readUTF8([item] + 2, c);
                 }
             } else if ( && "Signature".equals(attrName)) {
                 signature = readUTF8(v + 6, c);
             } else if ( && "RuntimeVisibleAnnotations".equals(attrName)) {
                 anns = v + 6;
             } else if ("Deprecated".equals(attrName)) {
                 access |= .;
             } else if ("Synthetic".equals(attrName)) {
                 access |= .;
             } else if ("SourceDebugExtension".equals(attrName)) {
                 int len = readInt(v + 2);
                 sourceDebug = readUTF(v + 6, lennew char[len]);
             } else if ( && "RuntimeInvisibleAnnotations".equals(attrName)) {
                 ianns = v + 6;
             } else {
                 attr = readAttribute(attrs,
                         attrName,
                         v + 6,
                         readInt(v + 2),
                         c,
                         -1,
                         null);
                 if (attr != null) {
                     attr.next = cattrs;
                     cattrs = attr;
                 }
             }
             v += 6 + readInt(v + 2);
         }
         // calls the visit method
         classVisitor.visit(readInt(4),
                 access,
                 name,
                 signature,
                 superClassName,
                 implementedItfs);
 
         // calls the visitSource method
         if (!skipDebug && (sourceFile != null || sourceDebug != null)) {
             classVisitor.visitSource(sourceFilesourceDebug);
         }
 
         // calls the visitOuterClass method
         if (enclosingOwner != null) {
             classVisitor.visitOuterClass(enclosingOwner,
                     enclosingName,
                     enclosingDesc);
         }
 
         // visits the class annotations
         if () {
             for (i = 1; i >= 0; --i) {
                 v = i == 0 ? ianns : anns;
                 if (v != 0) {
                     j = readUnsignedShort(v);
                     v += 2;
                     for (; j > 0; --j) {
                         v = readAnnotationValues(v + 2,
                                 c,
                                 true,
                                 classVisitor.visitAnnotation(readUTF8(vc), i != 0));
                     }
                 }
             }
         }
 
         // visits the class attributes
         while (cattrs != null) {
             attr = cattrs.next;
             cattrs.next = null;
             classVisitor.visitAttribute(cattrs);
             cattrs = attr;
         }
 
         // calls the visitInnerClass method
         if (w != 0) {
             i = readUnsignedShort(w);
             w += 2;
             for (; i > 0; --i) {
                 classVisitor.visitInnerClass(readUnsignedShort(w) == 0
                         ? null
                         : readClass(wc), readUnsignedShort(w + 2) == 0
                         ? null
                         : readClass(w + 2, c), readUnsignedShort(w + 4) == 0
                         ? null
                         : readUTF8(w + 4, c), readUnsignedShort(w + 6));
                 w += 8;
             }
         }
 
         // visits the fields
         i = readUnsignedShort(u);
         u += 2;
         for (; i > 0; --i) {
             access = readUnsignedShort(u);
             name = readUTF8(u + 2, c);
             desc = readUTF8(u + 4, c);
             // visits the field's attributes and looks for a ConstantValue
             // attribute
             int fieldValueItem = 0;
             signature = null;
             anns = 0;
             ianns = 0;
             cattrs = null;
 
             j = readUnsignedShort(u + 6);
             u += 8;
             for (; j > 0; --j) {
                 attrName = readUTF8(uc);
                 // tests are sorted in decreasing frequency order
                 // (based on frequencies observed on typical classes)
                 if ("ConstantValue".equals(attrName)) {
                     fieldValueItem = readUnsignedShort(u + 6);
                 } else if ( && "Signature".equals(attrName)) {
                     signature = readUTF8(u + 6, c);
                 } else if ("Deprecated".equals(attrName)) {
                     access |= .;
                 } else if ("Synthetic".equals(attrName)) {
                     access |= .;
                 } else if ( && "RuntimeVisibleAnnotations".equals(attrName)) {
                     anns = u + 6;
                 } else if ( && "RuntimeInvisibleAnnotations".equals(attrName)) {
                     ianns = u + 6;
                 } else {
                     attr = readAttribute(attrs,
                             attrName,
                             u + 6,
                             readInt(u + 2),
                             c,
                             -1,
                             null);
                     if (attr != null) {
                         attr.next = cattrs;
                         cattrs = attr;
                     }
                 }
                 u += 6 + readInt(u + 2);
             }
             // visits the field
             FieldVisitor fv = classVisitor.visitField(access,
                     name,
                     desc,
                     signature,
                     fieldValueItem == 0 ? null : readConst(fieldValueItemc));
             // visits the field annotations and attributes
             if (fv != null) {
                 if () {
                     for (j = 1; j >= 0; --j) {
                         v = j == 0 ? ianns : anns;
                         if (v != 0) {
                             k = readUnsignedShort(v);
                             v += 2;
                             for (; k > 0; --k) {
                                 v = readAnnotationValues(v + 2,
                                         c,
                                         true,
                                         fv.visitAnnotation(readUTF8(vc), j != 0));
                             }
                         }
                     }
                 }
                 while (cattrs != null) {
                     attr = cattrs.next;
                     cattrs.next = null;
                     fv.visitAttribute(cattrs);
                     cattrs = attr;
                 }
                 fv.visitEnd();
             }
         }
 
         // visits the methods
         i = readUnsignedShort(u);
         u += 2;
         for (; i > 0; --i) {
             int u0 = u + 6;
             access = readUnsignedShort(u);
             name = readUTF8(u + 2, c);
             desc = readUTF8(u + 4, c);
             signature = null;
             anns = 0;
             ianns = 0;
             int dann = 0;
             int mpanns = 0;
             int impanns = 0;
             cattrs = null;
             v = 0;
             w = 0;
 
             // looks for Code and Exceptions attributes
             j = readUnsignedShort(u + 6);
             u += 8;
             for (; j > 0; --j) {
                 attrName = readUTF8(uc);
                 int attrSize = readInt(u + 2);
                 u += 6;
                 // tests are sorted in decreasing frequency order
                 // (based on frequencies observed on typical classes)
                 if ("Code".equals(attrName)) {
                     if (!skipCode) {
                         v = u;
                     }
                 } else if ("Exceptions".equals(attrName)) {
                     w = u;
                 } else if ( && "Signature".equals(attrName)) {
                     signature = readUTF8(uc);
                 } else if ("Deprecated".equals(attrName)) {
                     access |= .;
                 } else if ( && "RuntimeVisibleAnnotations".equals(attrName)) {
                     anns = u;
                 } else if ( && "AnnotationDefault".equals(attrName)) {
                     dann = u;
                 } else if ("Synthetic".equals(attrName)) {
                     access |= .;
                 } else if ( && "RuntimeInvisibleAnnotations".equals(attrName)) {
                     ianns = u;
                 } else if ( && "RuntimeVisibleParameterAnnotations".equals(attrName))
                 {
                     mpanns = u;
                 } else if ( && "RuntimeInvisibleParameterAnnotations".equals(attrName))
                 {
                     impanns = u;
                 } else {
                     attr = readAttribute(attrs,
                             attrName,
                             u,
                             attrSize,
                             c,
                             -1,
                             null);
                     if (attr != null) {
                         attr.next = cattrs;
                         cattrs = attr;
                     }
                 }
                 u += attrSize;
             }
             // reads declared exceptions
             String[] exceptions;
             if (w == 0) {
                 exceptions = null;
             } else {
                 exceptions = new String[readUnsignedShort(w)];
                 w += 2;
                 for (j = 0; j < exceptions.length; ++j) {
                     exceptions[j] = readClass(wc);
                     w += 2;
                 }
             }
 
             // visits the method's code, if any
             MethodVisitor mv = classVisitor.visitMethod(access,
                     name,
                     desc,
                     signature,
                     exceptions);
 
             if (mv != null) {
                 /*
                  * if the returned MethodVisitor is in fact a MethodWriter, it
                  * means there is no method adapter between the reader and the
                  * writer. If, in addition, the writer's constant pool was
                  * copied from this reader (mw.cw.cr == this), and the signature
                  * and exceptions of the method have not been changed, then it
                  * is possible to skip all visit events and just copy the
                  * original code of the method to the writer (the access, name
                  * and descriptor can have been changed, this is not important
                  * since they are not copied as is from the reader).
                  */
                 if ( && mv instanceof MethodWriter) {
                     MethodWriter mw = (MethodWritermv;
                     if (mw.cw.cr == this) {
                         if (signature == mw.signature) {
                             boolean sameExceptions = false;
                             if (exceptions == null) {
                                 sameExceptions = mw.exceptionCount == 0;
                             } else {
                                 if (exceptions.length == mw.exceptionCount) {
                                     sameExceptions = true;
                                     for (j = exceptions.length - 1; j >= 0; --j)
                                     {
                                         w -= 2;
                                         if (mw.exceptions[j] != readUnsignedShort(w))
                                         {
                                             sameExceptions = false;
                                             break;
                                         }
                                     }
                                 }
                             }
                             if (sameExceptions) {
                                 /*
                                  * we do not copy directly the code into
                                  * MethodWriter to save a byte array copy
                                  * operation. The real copy will be done in
                                  * ClassWriter.toByteArray().
                                  */
                                 mw.classReaderOffset = u0;
                                 mw.classReaderLength = u - u0;
                                 continue;
                             }
                         }
                     }
                 }
 
                 if ( && dann != 0) {
                     AnnotationVisitor dv = mv.visitAnnotationDefault();
                     readAnnotationValue(danncnulldv);
                     if (dv != null) {
                         dv.visitEnd();
                     }
                 }
                 if () {
                     for (j = 1; j >= 0; --j) {
                         w = j == 0 ? ianns : anns;
                         if (w != 0) {
                             k = readUnsignedShort(w);
                             w += 2;
                             for (; k > 0; --k) {
                                 w = readAnnotationValues(w + 2,
                                         c,
                                         true,
                                         mv.visitAnnotation(readUTF8(wc), j != 0));
                             }
                         }
                     }
                 }
                 if ( && mpanns != 0) {
                     readParameterAnnotations(mpannsdescctruemv);
                 }
                 if ( && impanns != 0) {
                     readParameterAnnotations(impannsdesccfalsemv);
                 }
                 while (cattrs != null) {
                     attr = cattrs.next;
                     cattrs.next = null;
                     mv.visitAttribute(cattrs);
                     cattrs = attr;
                 }
             }
 
             if (mv != null && v != 0) {
                 int maxStack = readUnsignedShort(v);
                 int maxLocals = readUnsignedShort(v + 2);
                 int codeLength = readInt(v + 4);
                 v += 8;
 
                 int codeStart = v;
                 int codeEnd = v + codeLength;
 
                 mv.visitCode();
 
                 // 1st phase: finds the labels
                 int label;
                 Label[] labels = new Label[codeLength + 2];
                 readLabel(codeLength + 1, labels);
                 while (v < codeEnd) {
                     w = v - codeStart;
                     int opcode = b[v] & 0xFF;
                     switch (.[opcode]) {
                         case .:
                         case .:
                             v += 1;
                             break;
                         case .:
                             readLabel(w + readShort(v + 1), labels);
                             v += 3;
                             break;
                         case .:
                             readLabel(w + readInt(v + 1), labels);
                             v += 5;
                             break;
                         case .:
                             opcode = b[v + 1] & 0xFF;
                             if (opcode == .) {
                                 v += 6;
                             } else {
                                 v += 4;
                             }
                             break;
                         case .:
                             // skips 0 to 3 padding bytes*
                             v = v + 4 - (w & 3);
                             // reads instruction
                             readLabel(w + readInt(v), labels);
                             j = readInt(v + 8) - readInt(v + 4) + 1;
                             v += 12;
                             for (; j > 0; --j) {
                                 readLabel(w + readInt(v), labels);
                                 v += 4;
                             }
                             break;
                         case .:
                             // skips 0 to 3 padding bytes*
                             v = v + 4 - (w & 3);
                             // reads instruction
                             readLabel(w + readInt(v), labels);
                             j = readInt(v + 4);
                             v += 8;
                             for (; j > 0; --j) {
                                 readLabel(w + readInt(v + 4), labels);
                                 v += 8;
                             }
                             break;
                         case .:
                         case .:
                         case .:
                             v += 2;
                             break;
                         case .:
                         case .:
                         case .:
                         case .:
                         case .:
                             v += 3;
                             break;
                         case .:
                             v += 5;
                             break;
                         // case MANA_INSN:
                         default:
                             v += 4;
                             break;
                     }
                 }
                 // parses the try catch entries
                 j = readUnsignedShort(v);
                 v += 2;
                 for (; j > 0; --j) {
                     Label start = readLabel(readUnsignedShort(v), labels);
                     Label end = readLabel(readUnsignedShort(v + 2), labels);
                     Label handler = readLabel(readUnsignedShort(v + 4), labels);
                     int type = readUnsignedShort(v + 6);
                     if (type == 0) {
                         mv.visitTryCatchBlock(startendhandlernull);
                     } else {
                         mv.visitTryCatchBlock(start,
                                 end,
                                 handler,
                                 readUTF8([type], c));
                     }
                     v += 8;
                 }
                 // parses the local variable, line number tables, and code
                 // attributes
                 int varTable = 0;
                 int varTypeTable = 0;
                 int stackMap = 0;
                 int frameCount = 0;
                 int frameMode = 0;
                 int frameOffset = 0;
                 int frameLocalCount = 0;
                 int frameLocalDiff = 0;
                 int frameStackCount = 0;
                 Object[] frameLocal = null;
                 Object[] frameStack = null;
                 boolean zip = true;
                 cattrs = null;
                 j = readUnsignedShort(v);
                 v += 2;
                 for (; j > 0; --j) {
                     attrName = readUTF8(vc);
                     if ("LocalVariableTable".equals(attrName)) {
                         if (!skipDebug) {
                             varTable = v + 6;
                             k = readUnsignedShort(v + 6);
                             w = v + 8;
                             for (; k > 0; --k) {
                                 label = readUnsignedShort(w);
                                 if (labels[label] == null) {
                                     readLabel(labellabels). |= .;
                                 }
                                 label += readUnsignedShort(w + 2);
                                 if (labels[label] == null) {
                                     readLabel(labellabels). |= .;
                                 }
                                 w += 10;
                            }
                        }
                    } else if ("LocalVariableTypeTable".equals(attrName)) {
                        varTypeTable = v + 6;
                    } else if ("LineNumberTable".equals(attrName)) {
                        if (!skipDebug) {
                            k = readUnsignedShort(v + 6);
                            w = v + 8;
                            for (; k > 0; --k) {
                                label = readUnsignedShort(w);
                                if (labels[label] == null) {
                                    readLabel(labellabels). |= .;
                                }
                                labels[label]. = readUnsignedShort(w + 2);
                                w += 4;
                            }
                        }
                    } else if ( && "StackMapTable".equals(attrName)) {
                        if ((flags & ) == 0) {
                            stackMap = v + 8;
                            frameCount = readUnsignedShort(v + 6);
                        }
                        /*
                         * here we do not extract the labels corresponding to
                         * the attribute content. This would require a full
                         * parsing of the attribute, which would need to be
                         * repeated in the second phase (see below). Instead the
                         * content of the attribute is read one frame at a time
                         * (i.e. after a frame has been visited, the next frame
                         * is read), and the labels it contains are also
                         * extracted one frame at a time. Thanks to the ordering
                         * of frames, having only a "one frame lookahead" is not
                         * a problem, i.e. it is not possible to see an offset
                         * smaller than the offset of the current insn and for
                         * which no Label exist.
                         */
                        // TODO true for frame offsets,
                        // but for UNINITIALIZED type offsets?
                    } else if ( && "StackMap".equals(attrName)) {
                        if ((flags & ) == 0) {
                            stackMap = v + 8;
                            frameCount = readUnsignedShort(v + 6);
                            zip = false;
                        }
                        /*
                         * IMPORTANT! here we assume that the frames are
                         * ordered, as in the StackMapTable attribute, although
                         * this is not guaranteed by the attribute format.
                         */
                    } else {
                        for (k = 0; k < attrs.length; ++k) {
                            if (attrs[k]..equals(attrName)) {
                                attr = attrs[k].read(this,
                                        v + 6,
                                        readInt(v + 2),
                                        c,
                                        codeStart - 8,
                                        labels);
                                if (attr != null) {
                                    attr.next = cattrs;
                                    cattrs = attr;
                                }
                            }
                        }
                    }
                    v += 6 + readInt(v + 2);
                }
                // 2nd phase: visits each instruction
                if ( && stackMap != 0) {
                    // creates the very first (implicit) frame from the method
                    // descriptor
                    frameLocal = new Object[maxLocals];
                    frameStack = new Object[maxStack];
                    if (unzip) {
                        int local = 0;
                        if ((access & .) == 0) {
                            if ("<init>".equals(name)) {
                                frameLocal[local++] = .;
                            } else {
                                frameLocal[local++] = readClass( + 2, c);
                            }
                        }
                        j = 1;
                        loop: while (true) {
                            k = j;
                            switch (desc.charAt(j++)) {
                                case 'Z':
                                case 'C':
                                case 'B':
                                case 'S':
                                case 'I':
                                    frameLocal[local++] = .;
                                    break;
                                case 'F':
                                    frameLocal[local++] = .;
                                    break;
                                case 'J':
                                    frameLocal[local++] = .;
                                    break;
                                case 'D':
                                    frameLocal[local++] = .;
                                    break;
                                case '[':
                                    while (desc.charAt(j) == '[') {
                                        ++j;
                                    }
                                    if (desc.charAt(j) == 'L') {
                                        ++j;
                                        while (desc.charAt(j) != ';') {
                                            ++j;
                                        }
                                    }
                                    frameLocal[local++] = desc.substring(k, ++j);
                                    break;
                                case 'L':
                                    while (desc.charAt(j) != ';') {
                                        ++j;
                                    }
                                    frameLocal[local++] = desc.substring(k + 1,
                                            j++);
                                    break;
                                default:
                                    break loop;
                            }
                        }
                        frameLocalCount = local;
                    }
                    /*
                     * for the first explicit frame the offset is not
                     * offset_delta + 1 but only offset_delta; setting the
                     * implicit frame offset to -1 allow the use of the
                     * "offset_delta + 1" rule in all cases
                     */
                    frameOffset = -1;
                }
                v = codeStart;
                Label l;
                while (v < codeEnd) {
                    w = v - codeStart;
                    l = labels[w];
                    if (l != null) {
                        mv.visitLabel(l);
                        if (!skipDebug && l.line > 0) {
                            mv.visitLineNumber(l.linel);
                        }
                    }
                    while ( && frameLocal != null
                            && (frameOffset == w || frameOffset == -1))
                    {
                        // if there is a frame for this offset,
                        // makes the visitor visit it,
                        // and reads the next frame if there is one.
                        if (!zip || unzip) {
                            mv.visitFrame(.,
                                    frameLocalCount,
                                    frameLocal,
                                    frameStackCount,
                                    frameStack);
                        } else if (frameOffset != -1) {
                            mv.visitFrame(frameMode,
                                    frameLocalDiff,
                                    frameLocal,
                                    frameStackCount,
                                    frameStack);
                        }
                        if (frameCount > 0) {
                            int tagdeltan;
                            if (zip) {
                                tag = b[stackMap++] & 0xFF;
                            } else {
                                tag = .;
                                frameOffset = -1;
                            }
                            frameLocalDiff = 0;
                            if (tag < .)
                            {
                                delta = tag;
                                frameMode = .;
                                frameStackCount = 0;
                            } else if (tag < .) {
                                delta = tag
                                        - .;
                                stackMap = readFrameType(frameStack,
                                        0,
                                        stackMap,
                                        c,
                                        labels);
                                frameMode = .;
                                frameStackCount = 1;
                            } else {
                                delta = readUnsignedShort(stackMap);
                                stackMap += 2;
                                if (tag == .)
                                {
                                    stackMap = readFrameType(frameStack,
                                            0,
                                            stackMap,
                                            c,
                                            labels);
                                    frameMode = .;
                                    frameStackCount = 1;
                                } else if (tag >= .
                                        && tag < .)
                                {
                                    frameMode = .;
                                    frameLocalDiff = .
                                            - tag;
                                    frameLocalCount -= frameLocalDiff;
                                    frameStackCount = 0;
                                } else if (tag == .)
                                {
                                    frameMode = .;
                                    frameStackCount = 0;
                                } else if (tag < .) {
             &nb