6817950: refactor ClassReader to improve attribute handling
authorjjg
Tue, 31 Mar 2009 11:07:55 -0700
changeset 2513 1cbbf23b22f9
parent 2512 70eb5f17c5f8
child 2514 f8929e3790b4
6817950: refactor ClassReader to improve attribute handling Reviewed-by: mcimadamore
langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java
langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Mon Mar 30 15:08:09 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Tue Mar 31 11:07:55 2009 -0700
@@ -25,8 +25,9 @@
 
 package com.sun.tools.javac.jvm;
 
-import com.sun.tools.javac.code.*;
-import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.util.Name;
+
 
 /** A JVM class file.
  *
@@ -86,6 +87,18 @@
     public final static int MAX_LOCALS = 0xffff;
     public final static int MAX_STACK = 0xffff;
 
+    public enum Version {
+        V45_3(45, 3), // base level for all attributes
+        V49(49, 0),   // JDK 1.5: enum, generics, annotations
+        V50(50, 0),   // JDK 1.6: stackmaps
+        V51(51, 0);   // JDK 1.7
+        Version(int major, int minor) {
+            this.major = major;
+            this.minor = minor;
+        }
+        public final int major, minor;
+    }
+
 
 /************************************************************************
  * String Translation Routines
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Mon Mar 30 15:08:09 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Tue Mar 31 11:07:55 2009 -0700
@@ -35,8 +35,11 @@
 import javax.lang.model.SourceVersion;
 import javax.tools.JavaFileObject;
 import javax.tools.JavaFileManager;
+import javax.tools.JavaFileManager.Location;
 import javax.tools.StandardJavaFileManager;
 
+import static javax.tools.StandardLocation.*;
+
 import com.sun.tools.javac.comp.Annotate;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Type.*;
@@ -49,9 +52,8 @@
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.TypeTags.*;
-import com.sun.tools.javac.jvm.ClassFile.NameAndType;
-import javax.tools.JavaFileManager.Location;
-import static javax.tools.StandardLocation.*;
+import static com.sun.tools.javac.jvm.ClassFile.*;
+import static com.sun.tools.javac.jvm.ClassFile.Version.*;
 
 /** This class provides operations to read a classfile into an internal
  *  representation. The internal representation is anchored in a
@@ -64,7 +66,7 @@
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
-public class ClassReader extends ClassFile implements Completer {
+public class ClassReader implements Completer {
     /** The context key for the class reader. */
     protected static final Context.Key<ClassReader> classReaderKey =
         new Context.Key<ClassReader>();
@@ -180,6 +182,11 @@
      */
     int[] poolIdx;
 
+    /** The major version number of the class file being read. */
+    int majorVersion;
+    /** The minor version number of the class file being read. */
+    int minorVersion;
+
     /** Get the ClassReader instance for this invocation. */
     public static ClassReader instance(Context context) {
         ClassReader instance = context.get(classReaderKey);
@@ -249,6 +256,8 @@
             : null;
 
         typevars = new Scope(syms.noSymbol);
+
+        initAttributeReaders();
     }
 
     /** Add member to class unless it is synthetic.
@@ -655,6 +664,7 @@
                                                          sbp - startSbp));
                 outer = new ClassType(outer, sigToTypes('>'), t) {
                         boolean completed = false;
+                        @Override
                         public Type getEnclosingType() {
                             if (!completed) {
                                 completed = true;
@@ -679,6 +689,7 @@
                             }
                             return super.getEnclosingType();
                         }
+                        @Override
                         public void setEnclosingType(Type outer) {
                             throw new UnsupportedOperationException();
                         }
@@ -822,6 +833,246 @@
  * Reading Attributes
  ***********************************************************************/
 
+    protected enum AttributeKind { CLASS, MEMBER };
+    protected abstract class AttributeReader {
+        AttributeReader(Name name, Version version, Set<AttributeKind> kinds) {
+            this.name = name;
+            this.version = version;
+            this.kinds = kinds;
+        }
+
+        boolean accepts(AttributeKind kind) {
+            return kinds.contains(kind) && majorVersion >= version.major;
+        }
+
+        abstract void read(Symbol sym, int attrLen);
+
+        final Name name;
+        final Version version;
+        final Set<AttributeKind> kinds;
+    }
+
+    protected Set<AttributeKind> CLASS_ATTRIBUTE =
+            EnumSet.of(AttributeKind.CLASS);
+    protected Set<AttributeKind> MEMBER_ATTRIBUTE =
+            EnumSet.of(AttributeKind.MEMBER);
+    protected Set<AttributeKind> CLASS_OR_MEMBER_ATTRIBUTE =
+            EnumSet.of(AttributeKind.CLASS, AttributeKind.MEMBER);
+
+    protected Map<Name, AttributeReader> attributeReaders = new HashMap<Name, AttributeReader>();
+
+    protected void initAttributeReaders() {
+        AttributeReader[] readers = {
+            // v45.3 attributes
+
+            new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    if (readAllOfClassFile || saveParameterNames)
+                        ((MethodSymbol)sym).code = readCode(sym);
+                    else
+                        bp = bp + attrLen;
+                }
+            },
+
+            new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    Object v = readPool(nextChar());
+                    // Ignore ConstantValue attribute if field not final.
+                    if ((sym.flags() & FINAL) != 0)
+                        ((VarSymbol) sym).setData(v);
+                }
+            },
+
+            new AttributeReader(names.Deprecated, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    sym.flags_field |= DEPRECATED;
+                }
+            },
+
+            new AttributeReader(names.Exceptions, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    int nexceptions = nextChar();
+                    List<Type> thrown = List.nil();
+                    for (int j = 0; j < nexceptions; j++)
+                        thrown = thrown.prepend(readClassSymbol(nextChar()).type);
+                    if (sym.type.getThrownTypes().isEmpty())
+                        sym.type.asMethodType().thrown = thrown.reverse();
+                }
+            },
+
+            new AttributeReader(names.InnerClasses, V45_3, CLASS_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    ClassSymbol c = (ClassSymbol) sym;
+                    readInnerClasses(c);
+                }
+            },
+
+            new AttributeReader(names.LocalVariableTable, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    int newbp = bp + attrLen;
+                    if (saveParameterNames) {
+                        // pick up parameter names from the variable table
+                        List<Name> parameterNames = List.nil();
+                        int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
+                        int endParam = firstParam + Code.width(sym.type.getParameterTypes());
+                        int numEntries = nextChar();
+                        for (int i=0; i<numEntries; i++) {
+                            int start_pc = nextChar();
+                            int length = nextChar();
+                            int nameIndex = nextChar();
+                            int sigIndex = nextChar();
+                            int register = nextChar();
+                            if (start_pc == 0 &&
+                                firstParam <= register &&
+                                register < endParam) {
+                                int index = firstParam;
+                                for (Type t : sym.type.getParameterTypes()) {
+                                    if (index == register) {
+                                        parameterNames = parameterNames.prepend(readName(nameIndex));
+                                        break;
+                                    }
+                                    index += Code.width(t);
+                                }
+                            }
+                        }
+                        parameterNames = parameterNames.reverse();
+                        ((MethodSymbol)sym).savedParameterNames = parameterNames;
+                    }
+                    bp = newbp;
+                }
+            },
+
+            new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    ClassSymbol c = (ClassSymbol) sym;
+                    Name n = readName(nextChar());
+                    c.sourcefile = new SourceFileObject(n, c.flatname);
+                }
+            },
+
+            new AttributeReader(names.Synthetic, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    // bridge methods are visible when generics not enabled
+                    if (allowGenerics || (sym.flags_field & BRIDGE) == 0)
+                        sym.flags_field |= SYNTHETIC;
+                }
+            },
+
+            // standard v49 attributes
+
+            new AttributeReader(names.EnclosingMethod, V49, CLASS_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    int newbp = bp + attrLen;
+                    readEnclosingMethodAttr(sym);
+                    bp = newbp;
+                }
+            },
+
+            new AttributeReader(names.Signature, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
+                @Override
+                boolean accepts(AttributeKind kind) {
+                    return super.accepts(kind) && allowGenerics;
+                }
+
+                void read(Symbol sym, int attrLen) {
+                    if (sym.kind == TYP) {
+                        ClassSymbol c = (ClassSymbol) sym;
+                        readingClassAttr = true;
+                        try {
+                            ClassType ct1 = (ClassType)c.type;
+                            assert c == currentOwner;
+                            ct1.typarams_field = readTypeParams(nextChar());
+                            ct1.supertype_field = sigToType();
+                            ListBuffer<Type> is = new ListBuffer<Type>();
+                            while (sigp != siglimit) is.append(sigToType());
+                            ct1.interfaces_field = is.toList();
+                        } finally {
+                            readingClassAttr = false;
+                        }
+                    } else {
+                        List<Type> thrown = sym.type.getThrownTypes();
+                        sym.type = readType(nextChar());
+                        //- System.err.println(" # " + sym.type);
+                        if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
+                            sym.type.asMethodType().thrown = thrown;
+
+                    }
+                }
+            },
+
+            // v49 annotation attributes
+
+            new AttributeReader(names.AnnotationDefault, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    attachAnnotationDefault(sym);
+                }
+            },
+
+            new AttributeReader(names.RuntimeInvisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    attachAnnotations(sym);
+                }
+            },
+
+            new AttributeReader(names.RuntimeInvisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    attachParameterAnnotations(sym);
+                }
+            },
+
+            new AttributeReader(names.RuntimeVisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    attachAnnotations(sym);
+                }
+            },
+
+            new AttributeReader(names.RuntimeVisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    attachParameterAnnotations(sym);
+                }
+            },
+
+            // additional "legacy" v49 attributes, superceded by flags
+
+            new AttributeReader(names.Annotation, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    if (allowAnnotations)
+                        sym.flags_field |= ANNOTATION;
+                }
+            },
+
+            new AttributeReader(names.Bridge, V49, MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    sym.flags_field |= BRIDGE;
+                    if (!allowGenerics)
+                        sym.flags_field &= ~SYNTHETIC;
+                }
+            },
+
+            new AttributeReader(names.Enum, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    sym.flags_field |= ENUM;
+                }
+            },
+
+            new AttributeReader(names.Varargs, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
+                void read(Symbol sym, int attrLen) {
+                    if (allowVarargs)
+                        sym.flags_field |= VARARGS;
+                }
+            }
+
+            // The following attributes for a Code attribute are not currently handled
+            // StackMapTable
+            // SourceDebugExtension
+            // LineNumberTable
+            // LocalVariableTypeTable
+        };
+
+        for (AttributeReader r: readers)
+            attributeReaders.put(r.name, r);
+    }
+
     /** Report unrecognized attribute.
      */
     void unrecognized(Name attrName) {
@@ -829,99 +1080,7 @@
             printCCF("ccf.unrecognized.attribute", attrName);
     }
 
-    /** Read member attribute.
-     */
-    void readMemberAttr(Symbol sym, Name attrName, int attrLen) {
-        //- System.err.println(" z " + sym + ", " + attrName + ", " + attrLen);
-        if (attrName == names.ConstantValue) {
-            Object v = readPool(nextChar());
-            // Ignore ConstantValue attribute if field not final.
-            if ((sym.flags() & FINAL) != 0)
-                ((VarSymbol)sym).setData(v);
-        } else if (attrName == names.Code) {
-            if (readAllOfClassFile || saveParameterNames)
-                ((MethodSymbol)sym).code = readCode(sym);
-            else
-                bp = bp + attrLen;
-        } else if (attrName == names.Exceptions) {
-            int nexceptions = nextChar();
-            List<Type> thrown = List.nil();
-            for (int j = 0; j < nexceptions; j++)
-                thrown = thrown.prepend(readClassSymbol(nextChar()).type);
-            if (sym.type.getThrownTypes().isEmpty())
-                sym.type.asMethodType().thrown = thrown.reverse();
-        } else if (attrName == names.Synthetic) {
-            // bridge methods are visible when generics not enabled
-            if (allowGenerics || (sym.flags_field & BRIDGE) == 0)
-                sym.flags_field |= SYNTHETIC;
-        } else if (attrName == names.Bridge) {
-            sym.flags_field |= BRIDGE;
-            if (!allowGenerics)
-                sym.flags_field &= ~SYNTHETIC;
-        } else if (attrName == names.Deprecated) {
-            sym.flags_field |= DEPRECATED;
-        } else if (attrName == names.Varargs) {
-            if (allowVarargs) sym.flags_field |= VARARGS;
-        } else if (attrName == names.Annotation) {
-            if (allowAnnotations) sym.flags_field |= ANNOTATION;
-        } else if (attrName == names.Enum) {
-            sym.flags_field |= ENUM;
-        } else if (allowGenerics && attrName == names.Signature) {
-            List<Type> thrown = sym.type.getThrownTypes();
-            sym.type = readType(nextChar());
-            //- System.err.println(" # " + sym.type);
-            if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
-                sym.type.asMethodType().thrown = thrown;
-        } else if (attrName == names.RuntimeVisibleAnnotations) {
-            attachAnnotations(sym);
-        } else if (attrName == names.RuntimeInvisibleAnnotations) {
-            attachAnnotations(sym);
-        } else if (attrName == names.RuntimeVisibleParameterAnnotations) {
-            attachParameterAnnotations(sym);
-        } else if (attrName == names.RuntimeInvisibleParameterAnnotations) {
-            attachParameterAnnotations(sym);
-        } else if (attrName == names.LocalVariableTable) {
-            int newbp = bp + attrLen;
-            if (saveParameterNames) {
-                // pick up parameter names from the variable table
-                List<Name> parameterNames = List.nil();
-                int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
-                int endParam = firstParam + Code.width(sym.type.getParameterTypes());
-                int numEntries = nextChar();
-                for (int i=0; i<numEntries; i++) {
-                    int start_pc = nextChar();
-                    int length = nextChar();
-                    int nameIndex = nextChar();
-                    int sigIndex = nextChar();
-                    int register = nextChar();
-                    if (start_pc == 0 &&
-                        firstParam <= register &&
-                        register < endParam) {
-                        int index = firstParam;
-                        for (Type t : sym.type.getParameterTypes()) {
-                            if (index == register) {
-                                parameterNames = parameterNames.prepend(readName(nameIndex));
-                                break;
-                            }
-                            index += Code.width(t);
-                        }
-                    }
-                }
-                parameterNames = parameterNames.reverse();
-                ((MethodSymbol)sym).savedParameterNames = parameterNames;
-            }
-            bp = newbp;
-        } else if (attrName == names.AnnotationDefault) {
-            attachAnnotationDefault(sym);
-        } else if (attrName == names.EnclosingMethod) {
-            int newbp = bp + attrLen;
-            readEnclosingMethodAttr(sym);
-            bp = newbp;
-        } else {
-            unrecognized(attrName);
-            bp = bp + attrLen;
-        }
-    }
+
 
     void readEnclosingMethodAttr(Symbol sym) {
         // sym is a nested class with an "Enclosing Method" attribute
@@ -1029,39 +1188,24 @@
     /** Read member attributes.
      */
     void readMemberAttrs(Symbol sym) {
+        readAttrs(sym, AttributeKind.MEMBER);
+    }
+
+    void readAttrs(Symbol sym, AttributeKind kind) {
         char ac = nextChar();
         for (int i = 0; i < ac; i++) {
             Name attrName = readName(nextChar());
             int attrLen = nextInt();
-            readMemberAttr(sym, attrName, attrLen);
+            AttributeReader r = attributeReaders.get(attrName);
+            if (r != null && r.accepts(kind))
+                r.read(sym, attrLen);
+            else  {
+                unrecognized(attrName);
+                bp = bp + attrLen;
+            }
         }
     }
 
-    /** Read class attribute.
-     */
-    void readClassAttr(ClassSymbol c, Name attrName, int attrLen) {
-        if (attrName == names.SourceFile) {
-            Name n = readName(nextChar());
-            c.sourcefile = new SourceFileObject(n, c.flatname);
-        } else if (attrName == names.InnerClasses) {
-            readInnerClasses(c);
-        } else if (allowGenerics && attrName == names.Signature) {
-            readingClassAttr = true;
-            try {
-                ClassType ct1 = (ClassType)c.type;
-                assert c == currentOwner;
-                ct1.typarams_field = readTypeParams(nextChar());
-                ct1.supertype_field = sigToType();
-                ListBuffer<Type> is = new ListBuffer<Type>();
-                while (sigp != siglimit) is.append(sigToType());
-                ct1.interfaces_field = is.toList();
-            } finally {
-                readingClassAttr = false;
-            }
-        } else {
-            readMemberAttr(c, attrName, attrLen);
-        }
-    }
     private boolean readingClassAttr = false;
     private List<Type> missingTypeVariables = List.nil();
     private List<Type> foundTypeVariables = List.nil();
@@ -1069,12 +1213,7 @@
     /** Read class attributes.
      */
     void readClassAttrs(ClassSymbol c) {
-        char ac = nextChar();
-        for (int i = 0; i < ac; i++) {
-            Name attrName = readName(nextChar());
-            int attrLen = nextInt();
-            readClassAttr(c, attrName, attrLen);
-        }
+        readAttrs(c, AttributeKind.CLASS);
     }
 
     /** Read code block.
@@ -1219,6 +1358,7 @@
             this.enumerator = enumerator;
         }
         public void accept(Visitor v) { ((ProxyVisitor)v).visitEnumAttributeProxy(this); }
+        @Override
         public String toString() {
             return "/*proxy enum*/" + enumType + "." + enumerator;
         }
@@ -1231,6 +1371,7 @@
             this.values = values;
         }
         public void accept(Visitor v) { ((ProxyVisitor)v).visitArrayAttributeProxy(this); }
+        @Override
         public String toString() {
             return "{" + values + "}";
         }
@@ -1246,6 +1387,7 @@
             this.values = values;
         }
         public void accept(Visitor v) { ((ProxyVisitor)v).visitCompoundAnnotationProxy(this); }
+        @Override
         public String toString() {
             StringBuffer buf = new StringBuffer();
             buf.append("@");
@@ -1414,6 +1556,7 @@
         final MethodSymbol sym;
         final Attribute value;
         final JavaFileObject classFile = currentClassFile;
+        @Override
         public String toString() {
             return " ClassReader store default for " + sym.owner + "." + sym + " is " + value;
         }
@@ -1437,6 +1580,7 @@
         final Symbol sym;
         final List<CompoundAnnotationProxy> l;
         final JavaFileObject classFile;
+        @Override
         public String toString() {
             return " ClassReader annotate " + sym.owner + "." + sym + " with " + l;
         }
@@ -1544,7 +1688,8 @@
 
         // prepare type variable table
         typevars = typevars.dup(currentOwner);
-        if (ct.getEnclosingType().tag == CLASS) enterTypevars(ct.getEnclosingType());
+        if (ct.getEnclosingType().tag == CLASS)
+            enterTypevars(ct.getEnclosingType());
 
         // read flags, or skip if this is an inner class
         long flags = adjustClassFlags(nextChar());
@@ -1632,8 +1777,8 @@
         if (magic != JAVA_MAGIC)
             throw badClassFile("illegal.start.of.class.file");
 
-        int minorVersion = nextChar();
-        int majorVersion = nextChar();
+        minorVersion = nextChar();
+        majorVersion = nextChar();
         int maxMajor = Target.MAX().majorVersion;
         int maxMinor = Target.MAX().minorVersion;
         if (majorVersion > maxMajor ||
@@ -1775,13 +1920,13 @@
         if (sym.kind == TYP) {
             ClassSymbol c = (ClassSymbol)sym;
             c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
-            boolean suppressFlush = this.suppressFlush;
-            this.suppressFlush = true;
+            boolean saveSuppressFlush = suppressFlush;
+            suppressFlush = true;
             try {
                 completeOwners(c.owner);
                 completeEnclosing(c);
             } finally {
-                this.suppressFlush = suppressFlush;
+                suppressFlush = saveSuppressFlush;
             }
             fillIn(c);
         } else if (sym.kind == PCK) {
@@ -2270,6 +2415,7 @@
             return URI.create(name.toString());
         }
 
+        @Override
         public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
             throw new UnsupportedOperationException();
         }