# HG changeset patch # User jjg # Date 1238522875 25200 # Node ID 1cbbf23b22f928e2ee7e5823915294af38ba8f4e # Parent 70eb5f17c5f8d6af39c419d86d145a89597d6759 6817950: refactor ClassReader to improve attribute handling Reviewed-by: mcimadamore diff -r 70eb5f17c5f8 -r 1cbbf23b22f9 langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.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 diff -r 70eb5f17c5f8 -r 1cbbf23b22f9 langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- 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. */ -public class ClassReader extends ClassFile implements Completer { +public class ClassReader implements Completer { /** The context key for the class reader. */ protected static final Context.Key classReaderKey = new Context.Key(); @@ -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 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 kinds; + } + + protected Set CLASS_ATTRIBUTE = + EnumSet.of(AttributeKind.CLASS); + protected Set MEMBER_ATTRIBUTE = + EnumSet.of(AttributeKind.MEMBER); + protected Set CLASS_OR_MEMBER_ATTRIBUTE = + EnumSet.of(AttributeKind.CLASS, AttributeKind.MEMBER); + + protected Map attributeReaders = new HashMap(); + + 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 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 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 is = new ListBuffer(); + while (sigp != siglimit) is.append(sigToType()); + ct1.interfaces_field = is.toList(); + } finally { + readingClassAttr = false; + } + } else { + List 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 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 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 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 is = new ListBuffer(); - 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 missingTypeVariables = List.nil(); private List 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 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(); }