[jboss-cvs] JBossAS SVN: r105877 - in projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect: util/objectweb/asm and 1 other directory.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Jun 9 12:51:34 EDT 2010


Author: kabir.khan at jboss.com
Date: 2010-06-09 12:51:33 -0400 (Wed, 09 Jun 2010)
New Revision: 105877

Removed:
   projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/util/objectweb/asm/ClassAdapter.java
Modified:
   projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmBehaviourBytes.java
   projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmClassBytes.java
   projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmFieldBytes.java
   projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/Util.java
   projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/util/objectweb/asm/ClassReader.java
Log:
[JBREFLECT-125] Don't load/visit things we are not interested in

Modified: projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmBehaviourBytes.java
===================================================================
--- projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmBehaviourBytes.java	2010-06-09 16:49:36 UTC (rev 105876)
+++ projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmBehaviourBytes.java	2010-06-09 16:51:33 UTC (rev 105877)
@@ -27,6 +27,7 @@
 
 import org.jboss.reflect.plugins.bytecode.bytes.BehaviourBytes;
 import org.jboss.reflect.util.objectweb.asm.AnnotationVisitor;
+import org.jboss.reflect.util.objectweb.asm.ClassReader;
 import org.jboss.reflect.util.objectweb.asm.MethodVisitor;
 
 /**
@@ -70,14 +71,14 @@
    public Annotation[][] getParameterAnnotations()
    {
       LoadParameterAnnotationsVisitor visitor = new LoadParameterAnnotationsVisitor();
-      getClazz().getReader().accept(visitor, AsmClassBytes.STANDARD_FLAGS);
+      getClazz().getReader().accept(visitor, AsmClassBytes.STANDARD_FLAGS | ClassReader.INCLUDE_MEHOD_PARAMETER_ANNOTATIONS);
       return visitor.getAnnotations();
    }
    
    public Annotation[] getAnnotations()
    {
       LoadBehaviourAnnotationsVisitor visitor = new LoadBehaviourAnnotationsVisitor();
-      getClazz().getReader().accept(visitor, AsmClassBytes.STANDARD_FLAGS);
+      getClazz().getReader().accept(visitor, AsmClassBytes.STANDARD_FLAGS | ClassReader.INCLUDE_METHOD_ANNOTATIONS);
       return visitor.getAnnotations();
    }
    

Modified: projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmClassBytes.java
===================================================================
--- projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmClassBytes.java	2010-06-09 16:49:36 UTC (rev 105876)
+++ projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmClassBytes.java	2010-06-09 16:51:33 UTC (rev 105877)
@@ -51,8 +51,11 @@
  */
 class AsmClassBytes extends JBossObject implements ClassBytes
 {
-   static final int STANDARD_FLAGS = ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES;
+   static final int STANDARD_FLAGS = ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES 
+      | ClassReader.SKIP_OUTER_CLASSES | ClassReader.SKIP_UNKNOWN_ATTRIBUTES;
    
+   static final int READ_FIELD_FLAGS = STANDARD_FLAGS | ClassReader.INCLUDE_FIELD_OVERVIEW;
+   
    static final ClassReaderCacheFactory CACHE_FACTORY = ClassReaderCacheFactory.createFromProperties();
    
    static final FieldBytes[] NO_FIELDS = new FieldBytes[0];
@@ -105,7 +108,7 @@
       if (fieldBytes == null)
       {
          FieldsVisitor visitor = new FieldsVisitor();
-         getReader().accept(visitor, STANDARD_FLAGS);
+         getReader().accept(visitor, STANDARD_FLAGS | ClassReader.INCLUDE_FIELD_OVERVIEW);
          fieldBytes = visitor.getFieldBytes();
       }
       return fieldBytes;
@@ -202,21 +205,21 @@
    public String getGenericSignature()
    {
       ClassSignatureVisitor visitor = new ClassSignatureVisitor();
-      getReader().accept(visitor, STANDARD_FLAGS);      
+      getReader().accept(visitor, STANDARD_FLAGS | ClassReader.INCLUDE_HEADER);      
       return visitor.getSignature();
    }
    
    public Annotation[] getAnnotations()
    {
       AnnotationsVisitor visitor = new AnnotationsVisitor();
-      getReader().accept(visitor, STANDARD_FLAGS);
+      getReader().accept(visitor, STANDARD_FLAGS | ClassReader.INCLUDE_CLASS_ANNOTATIONS);
       return visitor.getAnnotations();
    }
 
    private void initMethodsAndConstructors()
    {
       ConstructorAndMethodsVisitor visitor = new ConstructorAndMethodsVisitor();
-      getReader().accept(visitor, STANDARD_FLAGS);
+      getReader().accept(visitor, STANDARD_FLAGS | ClassReader.INCLUDE_METHOD_OVERVIEW);
       methodBytes = visitor.getMethodBytes();
       constructorBytes = visitor.getConstructorBytes();
    }

Modified: projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmFieldBytes.java
===================================================================
--- projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmFieldBytes.java	2010-06-09 16:49:36 UTC (rev 105876)
+++ projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/AsmFieldBytes.java	2010-06-09 16:51:33 UTC (rev 105877)
@@ -27,6 +27,7 @@
 
 import org.jboss.reflect.plugins.bytecode.bytes.FieldBytes;
 import org.jboss.reflect.util.objectweb.asm.AnnotationVisitor;
+import org.jboss.reflect.util.objectweb.asm.ClassReader;
 import org.jboss.reflect.util.objectweb.asm.FieldVisitor;
 import org.jboss.reflect.util.objectweb.asm.Opcodes;
 
@@ -46,7 +47,7 @@
    public Annotation[] getAnnotations()
    {
       LoadFieldAnnotationsVisitor visitor = new LoadFieldAnnotationsVisitor();
-      getClazz().getReader().accept(visitor, AsmClassBytes.STANDARD_FLAGS);
+      getClazz().getReader().accept(visitor, AsmClassBytes.STANDARD_FLAGS | ClassReader.INCLUDE_FIELD_ANNOTATIONS);
       return visitor.getAnnotations();
    }
 

Modified: projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/Util.java
===================================================================
--- projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/Util.java	2010-06-09 16:49:36 UTC (rev 105876)
+++ projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/bytecode/bytes/asm/Util.java	2010-06-09 16:51:33 UTC (rev 105877)
@@ -24,7 +24,6 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Array;
 import java.util.ArrayList;
-import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -33,8 +32,8 @@
 import org.jboss.reflect.plugins.bytecode.bytes.ClassBytes;
 import org.jboss.reflect.util.objectweb.asm.AnnotationVisitor;
 import org.jboss.reflect.util.objectweb.asm.Attribute;
+import org.jboss.reflect.util.objectweb.asm.ClassReader;
 import org.jboss.reflect.util.objectweb.asm.ClassVisitor;
-import org.jboss.reflect.util.objectweb.asm.ClassVisitorParts;
 import org.jboss.reflect.util.objectweb.asm.FieldVisitor;
 import org.jboss.reflect.util.objectweb.asm.Label;
 import org.jboss.reflect.util.objectweb.asm.MethodVisitor;
@@ -179,7 +178,7 @@
                {
                   defaults = new DefaultAnnotationAttributeReader(loader, allAnnotationAttributesReader);
                   if (classBytes instanceof AsmClassBytes)
-                     ((AsmClassBytes)classBytes).getReader().accept(defaults, AsmClassBytes.STANDARD_FLAGS);
+                     ((AsmClassBytes)classBytes).getReader().accept(defaults, AsmClassBytes.STANDARD_FLAGS | ClassReader.INCLUDE_DEFAULT_ANNOTATION_VALUES);
                }
                Object value = defaults.defaultAttributesByName.get(name);
                if (value == null)
@@ -206,8 +205,6 @@
       {
          Map<String, String> returnTypesByName = new HashMap<String, String>();
 
-         final static EnumSet<ClassVisitorParts> PARTS = EnumSet.noneOf(ClassVisitorParts.class);
-
          @Override
          public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
          {
@@ -217,11 +214,6 @@
             }
             return null;
          }
-
-         public EnumSet<ClassVisitorParts> getParts()
-         {
-            return PARTS;
-         }
       }
       
       private static class DefaultAnnotationAttributeReader extends EmptyVisitor
@@ -231,8 +223,6 @@
          final ClassLoader loader;
          final AllAnnotationAttributesReader allAnnotationAttributesReader;
          
-         final static EnumSet<ClassVisitorParts> PARTS = EnumSet.noneOf(ClassVisitorParts.class);
-         
          public DefaultAnnotationAttributeReader(ClassLoader loader, AllAnnotationAttributesReader allAnnotationAttributesReader)
          {
             this.loader = loader;
@@ -245,10 +235,6 @@
             return new AnnotationDefaultReader(name);
          }
 
-         public EnumSet<ClassVisitorParts> getParts()
-         {
-            return PARTS;
-         }
 //         @Override
 //         public void visitEnd()
 //         {

Deleted: projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/util/objectweb/asm/ClassAdapter.java
===================================================================
--- projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/util/objectweb/asm/ClassAdapter.java	2010-06-09 16:49:36 UTC (rev 105876)
+++ projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/util/objectweb/asm/ClassAdapter.java	2010-06-09 16:51:33 UTC (rev 105877)
@@ -1,121 +0,0 @@
-/***
- * 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.jboss.reflect.util.objectweb.asm;
-
-/**
- * An empty {@link ClassVisitor} that delegates to another {@link ClassVisitor}.
- * This class can be used as a super class to quickly implement usefull class
- * adapter classes, just by overriding the necessary methods.
- * 
- * @author Eric Bruneton
- */
-public class ClassAdapter implements ClassVisitor {
-
-    /**
-     * The {@link ClassVisitor} to which this adapter delegates calls.
-     */
-    protected ClassVisitor cv;
-
-    /**
-     * Constructs a new {@link ClassAdapter} object.
-     * 
-     * @param cv the class visitor to which this adapter must delegate calls.
-     */
-    public ClassAdapter(final ClassVisitor cv) {
-        this.cv = cv;
-    }
-
-    public void visit(
-        final int version,
-        final int access,
-        final String name,
-        final String signature,
-        final String superName,
-        final String[] interfaces)
-    {
-        cv.visit(version, access, name, signature, superName, interfaces);
-    }
-
-    public void visitSource(final String source, final String debug) {
-        cv.visitSource(source, debug);
-    }
-
-    public void visitOuterClass(
-        final String owner,
-        final String name,
-        final String desc)
-    {
-        cv.visitOuterClass(owner, name, desc);
-    }
-
-    public AnnotationVisitor visitAnnotation(
-        final String desc,
-        final boolean visible)
-    {
-        return cv.visitAnnotation(desc, visible);
-    }
-
-    public void visitAttribute(final Attribute attr) {
-        cv.visitAttribute(attr);
-    }
-
-    public void visitInnerClass(
-        final String name,
-        final String outerName,
-        final String innerName,
-        final int access)
-    {
-        cv.visitInnerClass(name, outerName, innerName, access);
-    }
-
-    public FieldVisitor visitField(
-        final int access,
-        final String name,
-        final String desc,
-        final String signature,
-        final Object value)
-    {
-        return cv.visitField(access, name, desc, signature, value);
-    }
-
-    public MethodVisitor visitMethod(
-        final int access,
-        final String name,
-        final String desc,
-        final String signature,
-        final String[] exceptions)
-    {
-        return cv.visitMethod(access, name, desc, signature, exceptions);
-    }
-
-    public void visitEnd() {
-        cv.visitEnd();
-    }
-}

Modified: projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/util/objectweb/asm/ClassReader.java
===================================================================
--- projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/util/objectweb/asm/ClassReader.java	2010-06-09 16:49:36 UTC (rev 105876)
+++ projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/util/objectweb/asm/ClassReader.java	2010-06-09 16:51:33 UTC (rev 105877)
@@ -104,7 +104,36 @@
     * ClassWriter which degrades performances quite a lot).
     */
    public static final int EXPAND_FRAMES = 8;
+   
+   //Extra flags for performance
+   public static final int SKIP_OUTER_CLASSES = 32;
+   
+   public static final int SKIP_INNER_CLASSES = 64;
 
+   public static final int SKIP_UNKNOWN_ATTRIBUTES = 128;
+   
+   public static final int INCLUDE_HEADER = 256;
+   
+   public static final int INCLUDE_CLASS_ANNOTATIONS = 512;
+   
+   public static final int INCLUDE_FIELD_OVERVIEW = 1024;
+   
+   public static final int INCLUDE_FIELD_ANNOTATIONS = 2048;
+   
+   public static final int INCLUDE_FIELD_UNKNOWN_ATTRIBUTES = 4096;
+   
+   public static final int INCLUDE_METHOD_OVERVIEW = 8192;
+   
+   public static final int INCLUDE_METHOD_ANNOTATIONS = 16384;
+   
+   public static final int INCLUDE_MEHOD_PARAMETER_ANNOTATIONS = 32768;
+   
+   public static final int INCLUDE_METHOD_UNKNOWN_ATTRIBUTES = 65536;
+
+   public static final int INCLUDE_DEFAULT_ANNOTATION_VALUES = 131072;
+   
+   
+
    /**
     * The class to be parsed. <i>The content of this array must not be
     * modified. This field is intended for {@link Attribute} sub classes, and
@@ -462,40 +491,42 @@
     */
    public void accept(final ClassVisitor classVisitor, final Attribute[] attrs, final int flags)
    {
-      byte[] b = this.b; // the bytecode array
       char[] c = new char[maxStringLength]; // buffer used to read strings
-      int i, j, k; // loop variables
+      int i, j; // loop variables
       int u, v, w; // indexes in b
       Attribute attr;
 
       int access;
       String name;
-      String desc;
       String attrName;
       String signature;
       int anns = 0;
       int ianns = 0;
       Attribute cattrs = null;
 
+      boolean skipDebug = (flags & SKIP_DEBUG) != 0;
+      boolean skipOuterClasses = (flags & SKIP_OUTER_CLASSES) != 0;
+      boolean skipInnerClasses = (flags & SKIP_INNER_CLASSES)  != 0;
+      boolean includeHeader = (flags & INCLUDE_HEADER) != 0;
+      boolean includeClassAnnotations = (flags & INCLUDE_CLASS_ANNOTATIONS) != 0;
+      boolean skipUnknownAttributes = (flags & SKIP_UNKNOWN_ATTRIBUTES) != 0;
+      
       // visits the header
       u = header;
       access = readUnsignedShort(u);
       name = readClass(u + 2, c);
       v = items[readUnsignedShort(u + 4)];
-      String superClassName = v == 0 ? null : readUTF8(v, c);
+      String superClassName = v == 0 || includeHeader ? null : readUTF8(v, c);
       String[] implementedItfs = new String[readUnsignedShort(u + 6)];
       w = 0;
       u += 8;
       for (i = 0; i < implementedItfs.length; ++i)
       {
-         implementedItfs[i] = readClass(u, c);
+         if (includeHeader)
+            implementedItfs[i] = readClass(u, c);
          u += 2;
       }
 
-      boolean skipCode = (flags & SKIP_CODE) != 0;
-      boolean skipDebug = (flags & SKIP_DEBUG) != 0;
-      boolean unzip = (flags & EXPAND_FRAMES) != 0;
-
       // skips fields and methods
       v = u;
       i = readUnsignedShort(v);
@@ -537,7 +568,8 @@
          // (based on frequencies observed on typical classes)
          if ("SourceFile".equals(attrName))
          {
-            sourceFile = readUTF8(v + 6, c);
+            if (!skipDebug)
+               sourceFile = readUTF8(v + 6, c);
          }
          else if ("InnerClasses".equals(attrName))
          {
@@ -545,19 +577,23 @@
          }
          else if ("EnclosingMethod".equals(attrName))
          {
-            enclosingOwner = readClass(v + 6, c);
-            int item = readUnsignedShort(v + 8);
-            if (item != 0)
+            if (!skipOuterClasses)
             {
-               enclosingName = readUTF8(items[item], c);
-               enclosingDesc = readUTF8(items[item] + 2, c);
+               enclosingOwner = readClass(v + 6, c);
+               int item = readUnsignedShort(v + 8);
+               if (item != 0)
+               {
+                  enclosingName = readUTF8(items[item], c);
+                  enclosingDesc = readUTF8(items[item] + 2, c);
+               }
             }
          }
          else if (SIGNATURES && "Signature".equals(attrName))
          {
-            signature = readUTF8(v + 6, c);
+            if (includeHeader)
+               signature = readUTF8(v + 6, c);
          }
-         else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName))
+         else if (includeClassAnnotations && "RuntimeVisibleAnnotations".equals(attrName))
          {
             anns = v + 6;
          }
@@ -571,14 +607,17 @@
          }
          else if ("SourceDebugExtension".equals(attrName))
          {
-            int len = readInt(v + 2);
-            sourceDebug = readUTF(v + 6, len, new char[len]);
+            if (!skipDebug)
+            {
+               int len = readInt(v + 2);
+               sourceDebug = readUTF(v + 6, len, new char[len]);
+            }
          }
-         else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName))
+         else if (includeClassAnnotations && "RuntimeInvisibleAnnotations".equals(attrName))
          {
             ianns = v + 6;
          }
-         else
+         else if (!skipUnknownAttributes)
          {
             attr = readAttribute(attrs, attrName, v + 6, readInt(v + 2), c, -1, null);
             if (attr != null)
@@ -589,8 +628,11 @@
          }
          v += 6 + readInt(v + 2);
       }
+      
+      
       // calls the visit method
-      classVisitor.visit(readInt(4), access, name, signature, superClassName, implementedItfs);
+      if (includeHeader)
+         classVisitor.visit(readInt(4), access, name, signature, superClassName, implementedItfs);
 
       // calls the visitSource method
       if (!skipDebug && (sourceFile != null || sourceDebug != null))
@@ -599,13 +641,13 @@
       }
 
       // calls the visitOuterClass method
-      if (enclosingOwner != null)
+      if (enclosingOwner != null && !skipOuterClasses)
       {
          classVisitor.visitOuterClass(enclosingOwner, enclosingName, enclosingDesc);
       }
 
       // visits the class annotations
-      if (ANNOTATIONS)
+      if (includeClassAnnotations)
       {
          for (i = 1; i >= 0; --i)
          {
@@ -623,16 +665,19 @@
       }
 
       // visits the class attributes
-      while (cattrs != null)
+      if (!skipUnknownAttributes)
       {
-         attr = cattrs.next;
-         cattrs.next = null;
-         classVisitor.visitAttribute(cattrs);
-         cattrs = attr;
+         while (cattrs != null)
+         {
+            attr = cattrs.next;
+            cattrs.next = null;
+            classVisitor.visitAttribute(cattrs);
+            cattrs = attr;
+         }
       }
 
       // calls the visitInnerClass method
-      if (w != 0)
+      if (w != 0 && !skipInnerClasses)
       {
          i = readUnsignedShort(w);
          w += 2;
@@ -651,91 +696,7 @@
       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(u, c);
-            // tests are sorted in decreasing frequency order
-            // (based on frequencies observed on typical classes)
-            if ("ConstantValue".equals(attrName))
-            {
-               fieldValueItem = readUnsignedShort(u + 6);
-            }
-            else if (SIGNATURES && "Signature".equals(attrName))
-            {
-               signature = readUTF8(u + 6, c);
-            }
-            else if ("Deprecated".equals(attrName))
-            {
-               access |= Opcodes.ACC_DEPRECATED;
-            }
-            else if ("Synthetic".equals(attrName))
-            {
-               access |= Opcodes.ACC_SYNTHETIC;
-            }
-            else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName))
-            {
-               anns = u + 6;
-            }
-            else if (ANNOTATIONS && "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(fieldValueItem, c));
-         // visits the field annotations and attributes
-         if (fv != null)
-         {
-            if (ANNOTATIONS)
-            {
-               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(v, c), j != 0));
-                     }
-                  }
-               }
-            }
-            while (cattrs != null)
-            {
-               attr = cattrs.next;
-               cattrs.next = null;
-               fv.visitAttribute(cattrs);
-               cattrs = attr;
-            }
-            fv.visitEnd();
-         }
+         u = readField(classVisitor, flags, attrs, c, u);
       }
 
       // visits the methods
@@ -743,75 +704,110 @@
       u += 2;
       for (; i > 0; --i)
       {
-         int u0 = u + 6;
+         u = readMethod(classVisitor, flags, attrs, c, u);
+      }
+
+      // visits the end of the class
+      classVisitor.visitEnd();
+   }
+
+   private int readMethod(final ClassVisitor classVisitor, int flags, final Attribute[] attrs, char[] c, int u)
+   {
+      byte[] b = this.b; // the bytecode array
+      boolean skipCode = (flags & SKIP_CODE) != 0;
+      boolean unzip = (flags & EXPAND_FRAMES) != 0;
+      boolean skipDebug = (flags & EXPAND_FRAMES) != 0;
+      boolean includeMethodOverview = (flags & INCLUDE_METHOD_OVERVIEW) != 0;
+      boolean includeMethodAnnotations = (flags & INCLUDE_METHOD_ANNOTATIONS) != 0;
+      boolean includeMethodParameterAnnotations = (flags & INCLUDE_MEHOD_PARAMETER_ANNOTATIONS) != 0;
+      boolean includeAnnotationDefaultValues = (flags & INCLUDE_DEFAULT_ANNOTATION_VALUES) != 0;
+      boolean includeMethodUnknownAttributes = (flags & INCLUDE_METHOD_UNKNOWN_ATTRIBUTES) != 0;
+
+      int u0 = u + 6;
+      int access = 0;
+      String name = null;
+      String desc = null;
+      if (includeMethodOverview)
+      {
          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;
+      }
+      //TODO use index instead and update visitMethod to use that
+      name = readUTF8(u + 2, c);
+      desc = readUTF8(u + 4, c);
+      
+      
+      String signature = null;
+      int anns = 0;
+      int ianns = 0;
+      int dann = 0;
+      int mpanns = 0;
+      int impanns = 0;
+      Attribute cattrs = null;
+      Attribute attr;
+      int v = 0;
+      int w = 0;
+      int k = 0;
 
-         // looks for Code and Exceptions attributes
-         j = readUnsignedShort(u + 6);
-         u += 8;
-         for (; j > 0; --j)
+      // looks for Code and Exceptions attributes
+      int j = readUnsignedShort(u + 6);
+      u += 8;
+      for (; j > 0; --j)
+      {
+         String attrName = readUTF8(u, c);
+         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))
          {
-            attrName = readUTF8(u, c);
-            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)
             {
-               if (!skipCode)
-               {
-                  v = u;
-               }
+               v = u;
             }
-            else if ("Exceptions".equals(attrName))
-            {
-               w = u;
-            }
-            else if (SIGNATURES && "Signature".equals(attrName))
-            {
+         }
+         else if ("Exceptions".equals(attrName))
+         {
+            w = u;
+         }
+         else if (SIGNATURES && "Signature".equals(attrName))
+         {
+            //if (includeMethodOverview)   TODO add this once visitMethod() uses index
                signature = readUTF8(u, c);
-            }
-            else if ("Deprecated".equals(attrName))
-            {
+         }
+         else if ("Deprecated".equals(attrName))
+         {
+            if (includeMethodOverview)
                access |= Opcodes.ACC_DEPRECATED;
-            }
-            else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName))
-            {
+         }
+         else if (includeMethodAnnotations && "RuntimeVisibleAnnotations".equals(attrName))
+         {
                anns = u;
-            }
-            else if (ANNOTATIONS && "AnnotationDefault".equals(attrName))
-            {
-               dann = u;
-            }
-            else if ("Synthetic".equals(attrName))
-            {
+         }
+         else if (ANNOTATIONS && "AnnotationDefault".equals(attrName))
+         {
+            dann = u;
+         }
+         else if ("Synthetic".equals(attrName))
+         {
+            if (includeMethodOverview)
                access |= Opcodes.ACC_SYNTHETIC;
-            }
-            else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName))
+         }
+         else if (includeMethodAnnotations && "RuntimeInvisibleAnnotations".equals(attrName))
+         {
+            ianns = u;
+         }
+         else if (includeMethodParameterAnnotations && "RuntimeVisibleParameterAnnotations".equals(attrName))
+         {
+            mpanns = u;
+         }
+         else if (includeMethodParameterAnnotations && "RuntimeInvisibleParameterAnnotations".equals(attrName))
+         {
+            impanns = u;
+         }
+         else
+         {
+            if (includeMethodUnknownAttributes)
             {
-               ianns = u;
-            }
-            else if (ANNOTATIONS && "RuntimeVisibleParameterAnnotations".equals(attrName))
-            {
-               mpanns = u;
-            }
-            else if (ANNOTATIONS && "RuntimeInvisibleParameterAnnotations".equals(attrName))
-            {
-               impanns = u;
-            }
-            else
-            {
                attr = readAttribute(attrs, attrName, u, attrSize, c, -1, null);
                if (attr != null)
                {
@@ -819,10 +815,13 @@
                   cattrs = attr;
                }
             }
-            u += attrSize;
          }
-         // reads declared exceptions
-         String[] exceptions;
+         u += attrSize;
+      }
+      // reads declared exceptions
+      String[] exceptions = null;
+      if (includeMethodOverview)
+      {
          if (w == 0)
          {
             exceptions = null;
@@ -837,100 +836,104 @@
                w += 2;
             }
          }
+      }
 
-         // visits the method's code, if any
-         MethodVisitor mv = classVisitor.visitMethod(access, name, desc, signature, exceptions);
+      // visits the method's code, if any
+      MethodVisitor mv = classVisitor.visitMethod(access, name, desc, signature, exceptions);
 
-         if (mv != null)
+      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 (WRITER && mv instanceof MethodWriter)
          {
-            /*
-             * 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 (WRITER && mv instanceof MethodWriter)
+            MethodWriter mw = (MethodWriter) mv;
+            if (mw.cw.cr == this)
             {
-               MethodWriter mw = (MethodWriter) mv;
-               if (mw.cw.cr == this)
+               if (signature == mw.signature)
                {
-                  if (signature == mw.signature)
+                  boolean sameExceptions = false;
+                  if (exceptions == null)
                   {
-                     boolean sameExceptions = false;
-                     if (exceptions == null)
+                     sameExceptions = mw.exceptionCount == 0;
+                  }
+                  else
+                  {
+                     if (exceptions.length == mw.exceptionCount)
                      {
-                        sameExceptions = mw.exceptionCount == 0;
-                     }
-                     else
-                     {
-                        if (exceptions.length == mw.exceptionCount)
+                        sameExceptions = true;
+                        for (j = exceptions.length - 1; j >= 0; --j)
                         {
-                           sameExceptions = true;
-                           for (j = exceptions.length - 1; j >= 0; --j)
+                           w -= 2;
+                           if (mw.exceptions[j] != readUnsignedShort(w))
                            {
-                              w -= 2;
-                              if (mw.exceptions[j] != readUnsignedShort(w))
-                              {
-                                 sameExceptions = false;
-                                 break;
-                              }
+                              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 (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;
+                     return u;
+                  }
                }
             }
+         }
 
-            if (ANNOTATIONS && dann != 0)
+         if (includeAnnotationDefaultValues && dann != 0)
+         {
+            AnnotationVisitor dv = mv.visitAnnotationDefault();
+            readAnnotationValue(dann, c, null, dv);
+            if (dv != null)
             {
-               AnnotationVisitor dv = mv.visitAnnotationDefault();
-               readAnnotationValue(dann, c, null, dv);
-               if (dv != null)
-               {
-                  dv.visitEnd();
-               }
+               dv.visitEnd();
             }
-            if (ANNOTATIONS)
+         }
+         if (includeMethodAnnotations)
+         {
+            for (j = 1; j >= 0; --j)
             {
-               for (j = 1; j >= 0; --j)
+               w = j == 0 ? ianns : anns;
+               if (w != 0)
                {
-                  w = j == 0 ? ianns : anns;
-                  if (w != 0)
+                  k = readUnsignedShort(w);
+                  w += 2;
+                  for (; k > 0; --k)
                   {
-                     k = readUnsignedShort(w);
-                     w += 2;
-                     for (; k > 0; --k)
-                     {
-                        w = readAnnotationValues(w + 2, c, true, mv.visitAnnotation(readUTF8(w, c), j != 0));
-                     }
+                     w = readAnnotationValues(w + 2, c, true, mv.visitAnnotation(readUTF8(w, c), j != 0));
                   }
                }
             }
-            if (ANNOTATIONS && mpanns != 0)
-            {
-               readParameterAnnotations(mpanns, desc, c, true, mv);
-            }
-            if (ANNOTATIONS && impanns != 0)
-            {
-               readParameterAnnotations(impanns, desc, c, false, mv);
-            }
+         }
+         if (includeMethodParameterAnnotations && mpanns != 0)
+         {
+            readParameterAnnotations(mpanns, desc, c, true, mv);
+         }
+         if (includeMethodParameterAnnotations && impanns != 0)
+         {
+            readParameterAnnotations(impanns, desc, c, false, mv);
+         }
+         if (includeMethodUnknownAttributes)
+         {
             while (cattrs != null)
             {
                attr = cattrs.next;
@@ -939,646 +942,766 @@
                cattrs = attr;
             }
          }
+      }
 
-         if (mv != null && v != 0)
-         {
-            int maxStack = readUnsignedShort(v);
-            int maxLocals = readUnsignedShort(v + 2);
-            int codeLength = readInt(v + 4);
-            v += 8;
+      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;
+         int codeStart = v;
+         int codeEnd = v + codeLength;
 
-            mv.visitCode();
+         mv.visitCode();
 
-            // 1st phase: finds the labels
-            int label;
-            Label[] labels = new Label[codeLength + 2];
-            readLabel(codeLength + 1, labels);
-            while (v < codeEnd)
+         // 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 (ClassWriter.TYPE[opcode])
             {
-               w = v - codeStart;
-               int opcode = b[v] & 0xFF;
-               switch (ClassWriter.TYPE[opcode])
-               {
-                  case ClassWriter.NOARG_INSN :
-                  case ClassWriter.IMPLVAR_INSN :
-                     v += 1;
-                     break;
-                  case ClassWriter.LABEL_INSN :
-                     readLabel(w + readShort(v + 1), labels);
-                     v += 3;
-                     break;
-                  case ClassWriter.LABELW_INSN :
-                     readLabel(w + readInt(v + 1), labels);
-                     v += 5;
-                     break;
-                  case ClassWriter.WIDE_INSN :
-                     opcode = b[v + 1] & 0xFF;
-                     if (opcode == Opcodes.IINC)
-                     {
-                        v += 6;
-                     }
-                     else
-                     {
-                        v += 4;
-                     }
-                     break;
-                  case ClassWriter.TABL_INSN :
-                     // skips 0 to 3 padding bytes*
-                     v = v + 4 - (w & 3);
-                     // reads instruction
+               case ClassWriter.NOARG_INSN :
+               case ClassWriter.IMPLVAR_INSN :
+                  v += 1;
+                  break;
+               case ClassWriter.LABEL_INSN :
+                  readLabel(w + readShort(v + 1), labels);
+                  v += 3;
+                  break;
+               case ClassWriter.LABELW_INSN :
+                  readLabel(w + readInt(v + 1), labels);
+                  v += 5;
+                  break;
+               case ClassWriter.WIDE_INSN :
+                  opcode = b[v + 1] & 0xFF;
+                  if (opcode == Opcodes.IINC)
+                  {
+                     v += 6;
+                  }
+                  else
+                  {
+                     v += 4;
+                  }
+                  break;
+               case ClassWriter.TABL_INSN :
+                  // 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);
-                     j = readInt(v + 8) - readInt(v + 4) + 1;
-                     v += 12;
-                     for (; j > 0; --j)
-                     {
-                        readLabel(w + readInt(v), labels);
-                        v += 4;
-                     }
-                     break;
-                  case ClassWriter.LOOK_INSN :
-                     // skips 0 to 3 padding bytes*
-                     v = v + 4 - (w & 3);
-                     // reads instruction
-                     readLabel(w + readInt(v), labels);
-                     j = readInt(v + 4);
+                     v += 4;
+                  }
+                  break;
+               case ClassWriter.LOOK_INSN :
+                  // 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;
-                     for (; j > 0; --j)
-                     {
-                        readLabel(w + readInt(v + 4), labels);
-                        v += 8;
-                     }
-                     break;
-                  case ClassWriter.VAR_INSN :
-                  case ClassWriter.SBYTE_INSN :
-                  case ClassWriter.LDC_INSN :
-                     v += 2;
-                     break;
-                  case ClassWriter.SHORT_INSN :
-                  case ClassWriter.LDCW_INSN :
-                  case ClassWriter.FIELDORMETH_INSN :
-                  case ClassWriter.TYPE_INSN :
-                  case ClassWriter.IINC_INSN :
-                     v += 3;
-                     break;
-                  case ClassWriter.ITFDYNMETH_INSN :
-                     v += 5;
-                     break;
-                  // case MANA_INSN:
-                  default :
-                     v += 4;
-                     break;
-               }
+                  }
+                  break;
+               case ClassWriter.VAR_INSN :
+               case ClassWriter.SBYTE_INSN :
+               case ClassWriter.LDC_INSN :
+                  v += 2;
+                  break;
+               case ClassWriter.SHORT_INSN :
+               case ClassWriter.LDCW_INSN :
+               case ClassWriter.FIELDORMETH_INSN :
+               case ClassWriter.TYPE_INSN :
+               case ClassWriter.IINC_INSN :
+                  v += 3;
+                  break;
+               case ClassWriter.ITFDYNMETH_INSN :
+                  v += 5;
+                  break;
+               // case MANA_INSN:
+               default :
+                  v += 4;
+                  break;
             }
-            // parses the try catch entries
-            j = readUnsignedShort(v);
-            v += 2;
-            for (; j > 0; --j)
+         }
+         // 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)
             {
-               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(start, end, handler, null);
-               }
-               else
-               {
-                  mv.visitTryCatchBlock(start, end, handler, readUTF8(items[type], c));
-               }
-               v += 8;
+               mv.visitTryCatchBlock(start, end, handler, null);
             }
-            // 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)
+            else
             {
-               attrName = readUTF8(v, c);
-               if ("LocalVariableTable".equals(attrName))
+               mv.visitTryCatchBlock(start, end, handler, readUTF8(items[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)
+         {
+            String attrName = readUTF8(v, c);
+            if ("LocalVariableTable".equals(attrName))
+            {
+               if (!skipDebug)
                {
-                  if (!skipDebug)
+                  varTable = v + 6;
+                  k = readUnsignedShort(v + 6);
+                  w = v + 8;
+                  for (; k > 0; --k)
                   {
-                     varTable = v + 6;
-                     k = readUnsignedShort(v + 6);
-                     w = v + 8;
-                     for (; k > 0; --k)
+                     label = readUnsignedShort(w);
+                     if (labels[label] == null)
                      {
-                        label = readUnsignedShort(w);
-                        if (labels[label] == null)
-                        {
-                           readLabel(label, labels).status |= Label.DEBUG;
-                        }
-                        label += readUnsignedShort(w + 2);
-                        if (labels[label] == null)
-                        {
-                           readLabel(label, labels).status |= Label.DEBUG;
-                        }
-                        w += 10;
+                        readLabel(label, labels).status |= Label.DEBUG;
                      }
+                     label += readUnsignedShort(w + 2);
+                     if (labels[label] == null)
+                     {
+                        readLabel(label, labels).status |= Label.DEBUG;
+                     }
+                     w += 10;
                   }
                }
-               else if ("LocalVariableTypeTable".equals(attrName))
+            }
+            else if ("LocalVariableTypeTable".equals(attrName))
+            {
+               varTypeTable = v + 6;
+            }
+            else if ("LineNumberTable".equals(attrName))
+            {
+               if (!skipDebug)
                {
-                  varTypeTable = v + 6;
-               }
-               else if ("LineNumberTable".equals(attrName))
-               {
-                  if (!skipDebug)
+                  k = readUnsignedShort(v + 6);
+                  w = v + 8;
+                  for (; k > 0; --k)
                   {
-                     k = readUnsignedShort(v + 6);
-                     w = v + 8;
-                     for (; k > 0; --k)
+                     label = readUnsignedShort(w);
+                     if (labels[label] == null)
                      {
-                        label = readUnsignedShort(w);
-                        if (labels[label] == null)
-                        {
-                           readLabel(label, labels).status |= Label.DEBUG;
-                        }
-                        labels[label].line = readUnsignedShort(w + 2);
-                        w += 4;
+                        readLabel(label, labels).status |= Label.DEBUG;
                      }
+                     labels[label].line = readUnsignedShort(w + 2);
+                     w += 4;
                   }
                }
-               else if (FRAMES && "StackMapTable".equals(attrName))
+            }
+            else if (FRAMES && "StackMapTable".equals(attrName))
+            {
+               if ((flags & SKIP_FRAMES) == 0)
                {
-                  if ((flags & SKIP_FRAMES) == 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?
+                  stackMap = v + 8;
+                  frameCount = readUnsignedShort(v + 6);
                }
-               else if (FRAMES && "StackMap".equals(attrName))
+               /*
+                * 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 (FRAMES && "StackMap".equals(attrName))
+            {
+               if ((flags & SKIP_FRAMES) == 0)
                {
-                  if ((flags & SKIP_FRAMES) == 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.
-                   */
+                  stackMap = v + 8;
+                  frameCount = readUnsignedShort(v + 6);
+                  zip = false;
                }
-               else
+               /*
+                * 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)
                {
-                  for (k = 0; k < attrs.length; ++k)
+                  if (attrs[k].type.equals(attrName))
                   {
-                     if (attrs[k].type.equals(attrName))
+                     attr = attrs[k].read(this, v + 6, readInt(v + 2), c, codeStart - 8, labels);
+                     if (attr != null)
                      {
-                        attr = attrs[k].read(this, v + 6, readInt(v + 2), c, codeStart - 8, labels);
-                        if (attr != null)
-                        {
-                           attr.next = cattrs;
-                           cattrs = attr;
-                        }
+                        attr.next = cattrs;
+                        cattrs = attr;
                      }
                   }
                }
-               v += 6 + readInt(v + 2);
             }
+            v += 6 + readInt(v + 2);
+         }
 
-            // 2nd phase: visits each instruction
-            if (FRAMES && stackMap != 0)
+         // 2nd phase: visits each instruction
+         if (FRAMES && stackMap != 0)
+         {
+            // creates the very first (implicit) frame from the method
+            // descriptor
+            frameLocal = new Object[maxLocals];
+            frameStack = new Object[maxStack];
+            if (unzip)
             {
-               // 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 & Opcodes.ACC_STATIC) == 0)
                {
-                  int local = 0;
-                  if ((access & Opcodes.ACC_STATIC) == 0)
+                  if ("<init>".equals(name))
                   {
-                     if ("<init>".equals(name))
-                     {
-                        frameLocal[local++] = Opcodes.UNINITIALIZED_THIS;
-                     }
-                     else
-                     {
-                        frameLocal[local++] = readClass(header + 2, c);
-                     }
+                     frameLocal[local++] = Opcodes.UNINITIALIZED_THIS;
                   }
-                  j = 1;
-                  loop : while (true)
+                  else
                   {
-                     k = j;
-                     switch (desc.charAt(j++))
-                     {
-                        case 'Z' :
-                        case 'C' :
-                        case 'B' :
-                        case 'S' :
-                        case 'I' :
-                           frameLocal[local++] = Opcodes.INTEGER;
-                           break;
-                        case 'F' :
-                           frameLocal[local++] = Opcodes.FLOAT;
-                           break;
-                        case 'J' :
-                           frameLocal[local++] = Opcodes.LONG;
-                           break;
-                        case 'D' :
-                           frameLocal[local++] = Opcodes.DOUBLE;
-                           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' :
+                     frameLocal[local++] = readClass(header + 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++] = Opcodes.INTEGER;
+                        break;
+                     case 'F' :
+                        frameLocal[local++] = Opcodes.FLOAT;
+                        break;
+                     case 'J' :
+                        frameLocal[local++] = Opcodes.LONG;
+                        break;
+                     case 'D' :
+                        frameLocal[local++] = Opcodes.DOUBLE;
+                        break;
+                     case '[' :
+                        while (desc.charAt(j) == '[')
+                        {
+                           ++j;
+                        }
+                        if (desc.charAt(j) == 'L')
+                        {
+                           ++j;
                            while (desc.charAt(j) != ';')
                            {
                               ++j;
                            }
-                           frameLocal[local++] = desc.substring(k + 1, j++);
-                           break;
-                        default :
-                           break loop;
-                     }
+                        }
+                        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;
+               frameLocalCount = local;
             }
-            v = codeStart;
-            Label l;
-            while (v < codeEnd)
+            /*
+             * 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)
             {
-               w = v - codeStart;
+               mv.visitLabel(l);
+               if (!skipDebug && l.line > 0)
+               {
+                  mv.visitLineNumber(l.line, l);
+               }
+            }
 
-               l = labels[w];
-               if (l != null)
+            while (FRAMES && 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.visitLabel(l);
-                  if (!skipDebug && l.line > 0)
-                  {
-                     mv.visitLineNumber(l.line, l);
-                  }
+                  mv.visitFrame(Opcodes.F_NEW, frameLocalCount, frameLocal, frameStackCount, frameStack);
                }
+               else if (frameOffset != -1)
+               {
+                  mv.visitFrame(frameMode, frameLocalDiff, frameLocal, frameStackCount, frameStack);
+               }
 
-               while (FRAMES && frameLocal != null && (frameOffset == w || frameOffset == -1))
+               if (frameCount > 0)
                {
-                  // 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)
+                  int tag, delta, n;
+                  if (zip)
                   {
-                     mv.visitFrame(Opcodes.F_NEW, frameLocalCount, frameLocal, frameStackCount, frameStack);
+                     tag = b[stackMap++] & 0xFF;
                   }
-                  else if (frameOffset != -1)
+                  else
                   {
-                     mv.visitFrame(frameMode, frameLocalDiff, frameLocal, frameStackCount, frameStack);
+                     tag = MethodWriter.FULL_FRAME;
+                     frameOffset = -1;
                   }
-
-                  if (frameCount > 0)
+                  frameLocalDiff = 0;
+                  if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME)
                   {
-                     int tag, delta, n;
-                     if (zip)
+                     delta = tag;
+                     frameMode = Opcodes.F_SAME;
+                     frameStackCount = 0;
+                  }
+                  else if (tag < MethodWriter.RESERVED)
+                  {
+                     delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;
+                     stackMap = readFrameType(frameStack, 0, stackMap, c, labels);
+                     frameMode = Opcodes.F_SAME1;
+                     frameStackCount = 1;
+                  }
+                  else
+                  {
+                     delta = readUnsignedShort(stackMap);
+                     stackMap += 2;
+                     if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
                      {
-                        tag = b[stackMap++] & 0xFF;
+                        stackMap = readFrameType(frameStack, 0, stackMap, c, labels);
+                        frameMode = Opcodes.F_SAME1;
+                        frameStackCount = 1;
                      }
-                     else
+                     else if (tag >= MethodWriter.CHOP_FRAME && tag < MethodWriter.SAME_FRAME_EXTENDED)
                      {
-                        tag = MethodWriter.FULL_FRAME;
-                        frameOffset = -1;
+                        frameMode = Opcodes.F_CHOP;
+                        frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED - tag;
+                        frameLocalCount -= frameLocalDiff;
+                        frameStackCount = 0;
                      }
-                     frameLocalDiff = 0;
-                     if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME)
+                     else if (tag == MethodWriter.SAME_FRAME_EXTENDED)
                      {
-                        delta = tag;
                         frameMode = Opcodes.F_SAME;
                         frameStackCount = 0;
                      }
-                     else if (tag < MethodWriter.RESERVED)
+                     else if (tag < MethodWriter.FULL_FRAME)
                      {
-                        delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;
-                        stackMap = readFrameType(frameStack, 0, stackMap, c, labels);
-                        frameMode = Opcodes.F_SAME1;
-                        frameStackCount = 1;
+                        j = unzip ? frameLocalCount : 0;
+                        for (k = tag - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--)
+                        {
+                           stackMap = readFrameType(frameLocal, j++, stackMap, c, labels);
+                        }
+                        frameMode = Opcodes.F_APPEND;
+                        frameLocalDiff = tag - MethodWriter.SAME_FRAME_EXTENDED;
+                        frameLocalCount += frameLocalDiff;
+                        frameStackCount = 0;
                      }
                      else
-                     {
-                        delta = readUnsignedShort(stackMap);
+                     { // if (tag == FULL_FRAME) {
+                        frameMode = Opcodes.F_FULL;
+                        n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap);
                         stackMap += 2;
-                        if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
+                        for (j = 0; n > 0; n--)
                         {
-                           stackMap = readFrameType(frameStack, 0, stackMap, c, labels);
-                           frameMode = Opcodes.F_SAME1;
-                           frameStackCount = 1;
+                           stackMap = readFrameType(frameLocal, j++, stackMap, c, labels);
                         }
-                        else if (tag >= MethodWriter.CHOP_FRAME && tag < MethodWriter.SAME_FRAME_EXTENDED)
+                        n = frameStackCount = readUnsignedShort(stackMap);
+                        stackMap += 2;
+                        for (j = 0; n > 0; n--)
                         {
-                           frameMode = Opcodes.F_CHOP;
-                           frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED - tag;
-                           frameLocalCount -= frameLocalDiff;
-                           frameStackCount = 0;
+                           stackMap = readFrameType(frameStack, j++, stackMap, c, labels);
                         }
-                        else if (tag == MethodWriter.SAME_FRAME_EXTENDED)
-                        {
-                           frameMode = Opcodes.F_SAME;
-                           frameStackCount = 0;
-                        }
-                        else if (tag < MethodWriter.FULL_FRAME)
-                        {
-                           j = unzip ? frameLocalCount : 0;
-                           for (k = tag - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--)
-                           {
-                              stackMap = readFrameType(frameLocal, j++, stackMap, c, labels);
-                           }
-                           frameMode = Opcodes.F_APPEND;
-                           frameLocalDiff = tag - MethodWriter.SAME_FRAME_EXTENDED;
-                           frameLocalCount += frameLocalDiff;
-                           frameStackCount = 0;
-                        }
-                        else
-                        { // if (tag == FULL_FRAME) {
-                           frameMode = Opcodes.F_FULL;
-                           n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap);
-                           stackMap += 2;
-                           for (j = 0; n > 0; n--)
-                           {
-                              stackMap = readFrameType(frameLocal, j++, stackMap, c, labels);
-                           }
-                           n = frameStackCount = readUnsignedShort(stackMap);
-                           stackMap += 2;
-                           for (j = 0; n > 0; n--)
-                           {
-                              stackMap = readFrameType(frameStack, j++, stackMap, c, labels);
-                           }
-                        }
                      }
-                     frameOffset += delta + 1;
-                     readLabel(frameOffset, labels);
+                  }
+                  frameOffset += delta + 1;
+                  readLabel(frameOffset, labels);
 
-                     --frameCount;
+                  --frameCount;
+               }
+               else
+               {
+                  frameLocal = null;
+               }
+            }
+
+            int opcode = b[v] & 0xFF;
+            switch (ClassWriter.TYPE[opcode])
+            {
+               case ClassWriter.NOARG_INSN :
+                  mv.visitInsn(opcode);
+                  v += 1;
+                  break;
+               case ClassWriter.IMPLVAR_INSN :
+                  if (opcode > Opcodes.ISTORE)
+                  {
+                     opcode -= 59; // ISTORE_0
+                     mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3);
                   }
                   else
                   {
-                     frameLocal = null;
+                     opcode -= 26; // ILOAD_0
+                     mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
                   }
-               }
-
-               int opcode = b[v] & 0xFF;
-               switch (ClassWriter.TYPE[opcode])
-               {
-                  case ClassWriter.NOARG_INSN :
-                     mv.visitInsn(opcode);
-                     v += 1;
-                     break;
-                  case ClassWriter.IMPLVAR_INSN :
-                     if (opcode > Opcodes.ISTORE)
-                     {
-                        opcode -= 59; // ISTORE_0
-                        mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3);
-                     }
-                     else
-                     {
-                        opcode -= 26; // ILOAD_0
-                        mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
-                     }
-                     v += 1;
-                     break;
-                  case ClassWriter.LABEL_INSN :
-                     mv.visitJumpInsn(opcode, labels[w + readShort(v + 1)]);
-                     v += 3;
-                     break;
-                  case ClassWriter.LABELW_INSN :
-                     mv.visitJumpInsn(opcode - 33, labels[w + readInt(v + 1)]);
+                  v += 1;
+                  break;
+               case ClassWriter.LABEL_INSN :
+                  mv.visitJumpInsn(opcode, labels[w + readShort(v + 1)]);
+                  v += 3;
+                  break;
+               case ClassWriter.LABELW_INSN :
+                  mv.visitJumpInsn(opcode - 33, labels[w + readInt(v + 1)]);
+                  v += 5;
+                  break;
+               case ClassWriter.WIDE_INSN :
+                  opcode = b[v + 1] & 0xFF;
+                  if (opcode == Opcodes.IINC)
+                  {
+                     mv.visitIincInsn(readUnsignedShort(v + 2), readShort(v + 4));
+                     v += 6;
+                  }
+                  else
+                  {
+                     mv.visitVarInsn(opcode, readUnsignedShort(v + 2));
+                     v += 4;
+                  }
+                  break;
+               case ClassWriter.TABL_INSN :
+                  // skips 0 to 3 padding bytes
+                  v = v + 4 - (w & 3);
+                  // reads instruction
+                  label = w + readInt(v);
+                  int min = readInt(v + 4);
+                  int max = readInt(v + 8);
+                  v += 12;
+                  Label[] table = new Label[max - min + 1];
+                  for (j = 0; j < table.length; ++j)
+                  {
+                     table[j] = labels[w + readInt(v)];
+                     v += 4;
+                  }
+                  mv.visitTableSwitchInsn(min, max, labels[label], table);
+                  break;
+               case ClassWriter.LOOK_INSN :
+                  // skips 0 to 3 padding bytes
+                  v = v + 4 - (w & 3);
+                  // reads instruction
+                  label = w + readInt(v);
+                  j = readInt(v + 4);
+                  v += 8;
+                  int[] keys = new int[j];
+                  Label[] values = new Label[j];
+                  for (j = 0; j < keys.length; ++j)
+                  {
+                     keys[j] = readInt(v);
+                     values[j] = labels[w + readInt(v + 4)];
+                     v += 8;
+                  }
+                  mv.visitLookupSwitchInsn(labels[label], keys, values);
+                  break;
+               case ClassWriter.VAR_INSN :
+                  mv.visitVarInsn(opcode, b[v + 1] & 0xFF);
+                  v += 2;
+                  break;
+               case ClassWriter.SBYTE_INSN :
+                  mv.visitIntInsn(opcode, b[v + 1]);
+                  v += 2;
+                  break;
+               case ClassWriter.SHORT_INSN :
+                  mv.visitIntInsn(opcode, readShort(v + 1));
+                  v += 3;
+                  break;
+               case ClassWriter.LDC_INSN :
+                  mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
+                  v += 2;
+                  break;
+               case ClassWriter.LDCW_INSN :
+                  mv.visitLdcInsn(readConst(readUnsignedShort(v + 1), c));
+                  v += 3;
+                  break;
+               case ClassWriter.FIELDORMETH_INSN :
+               case ClassWriter.ITFDYNMETH_INSN :
+                  int cpIndex = items[readUnsignedShort(v + 1)];
+                  String iowner;
+                  // INVOKEDYNAMIC is receiverless
+                  if (opcode == Opcodes.INVOKEDYNAMIC)
+                  {
+                     iowner = Opcodes.INVOKEDYNAMIC_OWNER;
+                  }
+                  else
+                  {
+                     iowner = readClass(cpIndex, c);
+                     cpIndex = items[readUnsignedShort(cpIndex + 2)];
+                  }
+                  String iname = readUTF8(cpIndex, c);
+                  String idesc = readUTF8(cpIndex + 2, c);
+                  if (opcode < Opcodes.INVOKEVIRTUAL)
+                  {
+                     mv.visitFieldInsn(opcode, iowner, iname, idesc);
+                  }
+                  else
+                  {
+                     mv.visitMethodInsn(opcode, iowner, iname, idesc);
+                  }
+                  if (opcode == Opcodes.INVOKEINTERFACE || opcode == Opcodes.INVOKEDYNAMIC)
+                  {
                      v += 5;
-                     break;
-                  case ClassWriter.WIDE_INSN :
-                     opcode = b[v + 1] & 0xFF;
-                     if (opcode == Opcodes.IINC)
-                     {
-                        mv.visitIincInsn(readUnsignedShort(v + 2), readShort(v + 4));
-                        v += 6;
-                     }
-                     else
-                     {
-                        mv.visitVarInsn(opcode, readUnsignedShort(v + 2));
-                        v += 4;
-                     }
-                     break;
-                  case ClassWriter.TABL_INSN :
-                     // skips 0 to 3 padding bytes
-                     v = v + 4 - (w & 3);
-                     // reads instruction
-                     label = w + readInt(v);
-                     int min = readInt(v + 4);
-                     int max = readInt(v + 8);
-                     v += 12;
-                     Label[] table = new Label[max - min + 1];
-                     for (j = 0; j < table.length; ++j)
-                     {
-                        table[j] = labels[w + readInt(v)];
-                        v += 4;
-                     }
-                     mv.visitTableSwitchInsn(min, max, labels[label], table);
-                     break;
-                  case ClassWriter.LOOK_INSN :
-                     // skips 0 to 3 padding bytes
-                     v = v + 4 - (w & 3);
-                     // reads instruction
-                     label = w + readInt(v);
-                     j = readInt(v + 4);
-                     v += 8;
-                     int[] keys = new int[j];
-                     Label[] values = new Label[j];
-                     for (j = 0; j < keys.length; ++j)
-                     {
-                        keys[j] = readInt(v);
-                        values[j] = labels[w + readInt(v + 4)];
-                        v += 8;
-                     }
-                     mv.visitLookupSwitchInsn(labels[label], keys, values);
-                     break;
-                  case ClassWriter.VAR_INSN :
-                     mv.visitVarInsn(opcode, b[v + 1] & 0xFF);
-                     v += 2;
-                     break;
-                  case ClassWriter.SBYTE_INSN :
-                     mv.visitIntInsn(opcode, b[v + 1]);
-                     v += 2;
-                     break;
-                  case ClassWriter.SHORT_INSN :
-                     mv.visitIntInsn(opcode, readShort(v + 1));
+                  }
+                  else
+                  {
                      v += 3;
-                     break;
-                  case ClassWriter.LDC_INSN :
-                     mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
-                     v += 2;
-                     break;
-                  case ClassWriter.LDCW_INSN :
-                     mv.visitLdcInsn(readConst(readUnsignedShort(v + 1), c));
-                     v += 3;
-                     break;
-                  case ClassWriter.FIELDORMETH_INSN :
-                  case ClassWriter.ITFDYNMETH_INSN :
-                     int cpIndex = items[readUnsignedShort(v + 1)];
-                     String iowner;
-                     // INVOKEDYNAMIC is receiverless
-                     if (opcode == Opcodes.INVOKEDYNAMIC)
-                     {
-                        iowner = Opcodes.INVOKEDYNAMIC_OWNER;
-                     }
-                     else
-                     {
-                        iowner = readClass(cpIndex, c);
-                        cpIndex = items[readUnsignedShort(cpIndex + 2)];
-                     }
-                     String iname = readUTF8(cpIndex, c);
-                     String idesc = readUTF8(cpIndex + 2, c);
-                     if (opcode < Opcodes.INVOKEVIRTUAL)
-                     {
-                        mv.visitFieldInsn(opcode, iowner, iname, idesc);
-                     }
-                     else
-                     {
-                        mv.visitMethodInsn(opcode, iowner, iname, idesc);
-                     }
-                     if (opcode == Opcodes.INVOKEINTERFACE || opcode == Opcodes.INVOKEDYNAMIC)
-                     {
-                        v += 5;
-                     }
-                     else
-                     {
-                        v += 3;
-                     }
-                     break;
-                  case ClassWriter.TYPE_INSN :
-                     mv.visitTypeInsn(opcode, readClass(v + 1, c));
-                     v += 3;
-                     break;
-                  case ClassWriter.IINC_INSN :
-                     mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
-                     v += 3;
-                     break;
-                  // case MANA_INSN:
-                  default :
-                     mv.visitMultiANewArrayInsn(readClass(v + 1, c), b[v + 3] & 0xFF);
-                     v += 4;
-                     break;
-               }
+                  }
+                  break;
+               case ClassWriter.TYPE_INSN :
+                  mv.visitTypeInsn(opcode, readClass(v + 1, c));
+                  v += 3;
+                  break;
+               case ClassWriter.IINC_INSN :
+                  mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
+                  v += 3;
+                  break;
+               // case MANA_INSN:
+               default :
+                  mv.visitMultiANewArrayInsn(readClass(v + 1, c), b[v + 3] & 0xFF);
+                  v += 4;
+                  break;
             }
-            l = labels[codeEnd - codeStart];
-            if (l != null)
+         }
+         l = labels[codeEnd - codeStart];
+         if (l != null)
+         {
+            mv.visitLabel(l);
+         }
+         // visits the local variable tables
+         if (!skipDebug && varTable != 0)
+         {
+            int[] typeTable = null;
+            if (varTypeTable != 0)
             {
-               mv.visitLabel(l);
+               k = readUnsignedShort(varTypeTable) * 3;
+               w = varTypeTable + 2;
+               typeTable = new int[k];
+               while (k > 0)
+               {
+                  typeTable[--k] = w + 6; // signature
+                  typeTable[--k] = readUnsignedShort(w + 8); // index
+                  typeTable[--k] = readUnsignedShort(w); // start
+                  w += 10;
+               }
             }
-            // visits the local variable tables
-            if (!skipDebug && varTable != 0)
+            k = readUnsignedShort(varTable);
+            w = varTable + 2;
+            for (; k > 0; --k)
             {
-               int[] typeTable = null;
-               if (varTypeTable != 0)
+               int start = readUnsignedShort(w);
+               int length = readUnsignedShort(w + 2);
+               int index = readUnsignedShort(w + 8);
+               String vsignature = null;
+               if (typeTable != null)
                {
-                  k = readUnsignedShort(varTypeTable) * 3;
-                  w = varTypeTable + 2;
-                  typeTable = new int[k];
-                  while (k > 0)
+                  for (int a = 0; a < typeTable.length; a += 3)
                   {
-                     typeTable[--k] = w + 6; // signature
-                     typeTable[--k] = readUnsignedShort(w + 8); // index
-                     typeTable[--k] = readUnsignedShort(w); // start
-                     w += 10;
+                     if (typeTable[a] == start && typeTable[a + 1] == index)
+                     {
+                        vsignature = readUTF8(typeTable[a + 2], c);
+                        break;
+                     }
                   }
                }
-               k = readUnsignedShort(varTable);
-               w = varTable + 2;
-               for (; k > 0; --k)
+               mv.visitLocalVariable(readUTF8(w + 4, c), readUTF8(w + 6, c), vsignature, labels[start], labels[start
+                     + length], index);
+               w += 10;
+            }
+         }
+         // visits the other attributes
+         while (cattrs != null)
+         {
+            attr = cattrs.next;
+            cattrs.next = null;
+            mv.visitAttribute(cattrs);
+            cattrs = attr;
+         }
+         // visits the max stack and max locals values
+         mv.visitMaxs(maxStack, maxLocals);
+      }
+
+      if (mv != null)
+      {
+         mv.visitEnd();
+      }
+      return u;
+   }
+
+   private int readField(final ClassVisitor classVisitor, final int flags, final Attribute[] attrs, char[] c, int u)
+   {
+      boolean includeFieldOverview = (flags & INCLUDE_FIELD_OVERVIEW) != 0;
+      boolean includeFieldAnnotations = (flags & INCLUDE_FIELD_ANNOTATIONS) != 0;
+      boolean includeFieldUnknownAttributes = (flags & INCLUDE_FIELD_UNKNOWN_ATTRIBUTES)  != 0;
+      int j;
+      int k;
+      int v;
+      Attribute attr;
+      int access = 0;
+      String name = null;
+      String desc = null;
+      String attrName;
+      String signature;
+      int anns;
+      int ianns;
+      Attribute cattrs;
+      if (includeFieldOverview)
+      {
+         access = readUnsignedShort(u);
+         desc = readUTF8(u + 4, c);
+      }
+      //TODO use index instead and update visitField to use that
+      name = readUTF8(u + 2, 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(u, c);
+         // tests are sorted in decreasing frequency order
+         // (based on frequencies observed on typical classes)
+         if ("ConstantValue".equals(attrName))
+         {
+            if (includeFieldOverview)
+               fieldValueItem = readUnsignedShort(u + 6);
+         }
+         else if (SIGNATURES && "Signature".equals(attrName))
+         {
+            if (includeFieldOverview)
+               signature = readUTF8(u + 6, c);
+         }
+         else if ("Deprecated".equals(attrName))
+         {
+            if (includeFieldOverview)
+               access |= Opcodes.ACC_DEPRECATED;
+         }
+         else if ("Synthetic".equals(attrName))
+         {
+            if (includeFieldOverview)
+               access |= Opcodes.ACC_SYNTHETIC;
+         }
+         else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName))
+         {
+            if (includeFieldAnnotations)
+               anns = u + 6;
+         }
+         else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName))
+         {
+            if (includeFieldAnnotations)
+               ianns = u + 6;
+         }
+         else
+         {
+            if (includeFieldUnknownAttributes)
+            {
+               attr = readAttribute(attrs, attrName, u + 6, readInt(u + 2), c, -1, null);
+               if (attr != null)
                {
-                  int start = readUnsignedShort(w);
-                  int length = readUnsignedShort(w + 2);
-                  int index = readUnsignedShort(w + 8);
-                  String vsignature = null;
-                  if (typeTable != 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(fieldValueItem, c));
+      // visits the field annotations and attributes
+      if (fv != null)
+      {
+         if (includeFieldAnnotations)
+         {
+            for (j = 1; j >= 0; --j)
+            {
+               v = j == 0 ? ianns : anns;
+               if (v != 0)
+               {
+                  k = readUnsignedShort(v);
+                  v += 2;
+                  for (; k > 0; --k)
                   {
-                     for (int a = 0; a < typeTable.length; a += 3)
-                     {
-                        if (typeTable[a] == start && typeTable[a + 1] == index)
-                        {
-                           vsignature = readUTF8(typeTable[a + 2], c);
-                           break;
-                        }
-                     }
+                     v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), j != 0));
                   }
-                  mv.visitLocalVariable(readUTF8(w + 4, c), readUTF8(w + 6, c), vsignature, labels[start], labels[start
-                        + length], index);
-                  w += 10;
                }
             }
-            // visits the other attributes
+         }
+         if (includeFieldUnknownAttributes)
+         {
             while (cattrs != null)
             {
                attr = cattrs.next;
                cattrs.next = null;
-               mv.visitAttribute(cattrs);
+               fv.visitAttribute(cattrs);
                cattrs = attr;
             }
-            // visits the max stack and max locals values
-            mv.visitMaxs(maxStack, maxLocals);
          }
-
-         if (mv != null)
-         {
-            mv.visitEnd();
-         }
+         fv.visitEnd();
       }
-
-      // visits the end of the class
-      classVisitor.visitEnd();
+      return u;
    }
-
+   
    /**
     * Reads parameter annotations and makes the given visitor visit them.
     * 



More information about the jboss-cvs-commits mailing list