< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java

Print this page

        

@@ -34,11 +34,10 @@
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.IntFunction;
 
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.NestingKind;
 import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;

@@ -54,12 +53,12 @@
 import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.file.BaseFileManager;
 import com.sun.tools.javac.file.PathFileObject;
+import com.sun.tools.javac.jvm.ClassFile.NameAndType;
 import com.sun.tools.javac.jvm.ClassFile.Version;
-import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
 import com.sun.tools.javac.main.Option;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;

@@ -99,10 +98,15 @@
 
     /** Switch: verbose output.
      */
     boolean verbose;
 
+    /** Switch: read constant pool and code sections. This switch is initially
+     *  set to false but can be turned on from outside.
+     */
+    public boolean readAllOfClassFile = false;
+
     /** Switch: allow modules.
      */
     boolean allowModules;
 
    /** Lint option: warn about classfile issues

@@ -164,19 +168,24 @@
      */
     protected ModuleSymbol currentModule = null;
 
     /** The buffer containing the currently read class file.
      */
-    ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE);
+    byte[] buf = new byte[INITIAL_BUFFER_SIZE];
 
     /** The current input pointer.
      */
     protected int bp;
 
-    /** The pool reader.
+    /** The objects of the constant pool.
+     */
+    Object[] poolObj;
+
+    /** For every constant pool entry, an index into buf where the
+     *  defining section of the entry is found.
      */
-    PoolReader poolReader;
+    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;

@@ -312,33 +321,298 @@
  ***********************************************************************/
 
     /** Read a character.
      */
     char nextChar() {
-        char res = buf.getChar(bp);
-        bp += 2;
-        return res;
+        return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
     }
 
     /** Read a byte.
      */
     int nextByte() {
-        return buf.getByte(bp++) & 0xFF;
+        return buf[bp++] & 0xFF;
     }
 
     /** Read an integer.
      */
     int nextInt() {
-        int res = buf.getInt(bp);
-        bp += 4;
-        return res;
+        return
+            ((buf[bp++] & 0xFF) << 24) +
+            ((buf[bp++] & 0xFF) << 16) +
+            ((buf[bp++] & 0xFF) << 8) +
+            (buf[bp++] & 0xFF);
+    }
+
+    /** Extract a character at position bp from buf.
+     */
+    char getChar(int bp) {
+        return
+            (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
+    }
+
+    /** Extract an integer at position bp from buf.
+     */
+    int getInt(int bp) {
+        return
+            ((buf[bp] & 0xFF) << 24) +
+            ((buf[bp+1] & 0xFF) << 16) +
+            ((buf[bp+2] & 0xFF) << 8) +
+            (buf[bp+3] & 0xFF);
+    }
+
+
+    /** Extract a long integer at position bp from buf.
+     */
+    long getLong(int bp) {
+        DataInputStream bufin =
+            new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
+        try {
+            return bufin.readLong();
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /** Extract a float at position bp from buf.
+     */
+    float getFloat(int bp) {
+        DataInputStream bufin =
+            new DataInputStream(new ByteArrayInputStream(buf, bp, 4));
+        try {
+            return bufin.readFloat();
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /** Extract a double at position bp from buf.
+     */
+    double getDouble(int bp) {
+        DataInputStream bufin =
+            new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
+        try {
+            return bufin.readDouble();
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
     }
 
 /************************************************************************
  * Constant Pool Access
  ***********************************************************************/
 
+    /** Index all constant pool entries, writing their start addresses into
+     *  poolIdx.
+     */
+    void indexPool() {
+        poolIdx = new int[nextChar()];
+        poolObj = new Object[poolIdx.length];
+        int i = 1;
+        while (i < poolIdx.length) {
+            poolIdx[i++] = bp;
+            byte tag = buf[bp++];
+            switch (tag) {
+            case CONSTANT_Utf8: case CONSTANT_Unicode: {
+                int len = nextChar();
+                bp = bp + len;
+                break;
+            }
+            case CONSTANT_Class:
+            case CONSTANT_String:
+            case CONSTANT_MethodType:
+            case CONSTANT_Module:
+            case CONSTANT_Package:
+                bp = bp + 2;
+                break;
+            case CONSTANT_MethodHandle:
+                bp = bp + 3;
+                break;
+            case CONSTANT_Fieldref:
+            case CONSTANT_Methodref:
+            case CONSTANT_InterfaceMethodref:
+            case CONSTANT_NameandType:
+            case CONSTANT_Integer:
+            case CONSTANT_Float:
+            case CONSTANT_Dynamic:
+            case CONSTANT_InvokeDynamic:
+                bp = bp + 4;
+                break;
+            case CONSTANT_Long:
+            case CONSTANT_Double:
+                bp = bp + 8;
+                i++;
+                break;
+            default:
+                throw badClassFile("bad.const.pool.tag.at",
+                                   Byte.toString(tag),
+                                   Integer.toString(bp -1));
+            }
+        }
+    }
+
+    /** Read constant pool entry at start address i, use pool as a cache.
+     */
+    Object readPool(int i) {
+        Object result = poolObj[i];
+        if (result != null) return result;
+
+        int index = poolIdx[i];
+        if (index == 0) return null;
+
+        byte tag = buf[index];
+        switch (tag) {
+        case CONSTANT_Utf8:
+            poolObj[i] = names.fromUtf(buf, index + 3, getChar(index + 1));
+            break;
+        case CONSTANT_Unicode:
+            throw badClassFile("unicode.str.not.supported");
+        case CONSTANT_Class:
+            poolObj[i] = readClassOrType(getChar(index + 1));
+            break;
+        case CONSTANT_String:
+            // FIXME: (footprint) do not use toString here
+            poolObj[i] = readName(getChar(index + 1)).toString();
+            break;
+        case CONSTANT_Fieldref: {
+            ClassSymbol owner = readClassSymbol(getChar(index + 1));
+            NameAndType nt = readNameAndType(getChar(index + 3));
+            poolObj[i] = new VarSymbol(0, nt.name, nt.uniqueType.type, owner);
+            break;
+        }
+        case CONSTANT_Methodref:
+        case CONSTANT_InterfaceMethodref: {
+            ClassSymbol owner = readClassSymbol(getChar(index + 1));
+            NameAndType nt = readNameAndType(getChar(index + 3));
+            poolObj[i] = new MethodSymbol(0, nt.name, nt.uniqueType.type, owner);
+            break;
+        }
+        case CONSTANT_NameandType:
+            poolObj[i] = new NameAndType(
+                readName(getChar(index + 1)),
+                readType(getChar(index + 3)), types);
+            break;
+        case CONSTANT_Integer:
+            poolObj[i] = getInt(index + 1);
+            break;
+        case CONSTANT_Float:
+            poolObj[i] = Float.valueOf(getFloat(index + 1));
+            break;
+        case CONSTANT_Long:
+            poolObj[i] = Long.valueOf(getLong(index + 1));
+            break;
+        case CONSTANT_Double:
+            poolObj[i] = Double.valueOf(getDouble(index + 1));
+            break;
+        case CONSTANT_MethodHandle:
+            skipBytes(4);
+            break;
+        case CONSTANT_MethodType:
+            skipBytes(3);
+            break;
+        case CONSTANT_Dynamic:
+        case CONSTANT_InvokeDynamic:
+            skipBytes(5);
+            break;
+        case CONSTANT_Module:
+        case CONSTANT_Package:
+            // this is temporary for now: treat as a simple reference to the underlying Utf8.
+            poolObj[i] = readName(getChar(index + 1));
+            break;
+        default:
+            throw badClassFile("bad.const.pool.tag", Byte.toString(tag));
+        }
+        return poolObj[i];
+    }
+
+    /** Read signature and convert to type.
+     */
+    Type readType(int i) {
+        int index = poolIdx[i];
+        return sigToType(buf, index + 3, getChar(index + 1));
+    }
+
+    /** If name is an array type or class signature, return the
+     *  corresponding type; otherwise return a ClassSymbol with given name.
+     */
+    Object readClassOrType(int i) {
+        int index =  poolIdx[i];
+        int len = getChar(index + 1);
+        int start = index + 3;
+        Assert.check(buf[start] == '[' || buf[start + len - 1] != ';');
+        // by the above assertion, the following test can be
+        // simplified to (buf[start] == '[')
+        return (buf[start] == '[' || buf[start + len - 1] == ';')
+            ? (Object)sigToType(buf, start, len)
+            : (Object)enterClass(names.fromUtf(internalize(buf, start,
+                                                           len)));
+    }
+
+    /** Read signature and convert to type parameters.
+     */
+    List<Type> readTypeParams(int i) {
+        int index = poolIdx[i];
+        return sigToTypeParams(buf, index + 3, getChar(index + 1));
+    }
+
+    /** Read class entry.
+     */
+    ClassSymbol readClassSymbol(int i) {
+        Object obj = readPool(i);
+        if (obj != null && !(obj instanceof ClassSymbol))
+            throw badClassFile("bad.const.pool.entry",
+                               currentClassFile.toString(),
+                               "CONSTANT_Class_info", i);
+        return (ClassSymbol)obj;
+    }
+
+    Name readClassName(int i) {
+        int index = poolIdx[i];
+        if (index == 0) return null;
+        byte tag = buf[index];
+        if (tag != CONSTANT_Class) {
+            throw badClassFile("bad.const.pool.entry",
+                               currentClassFile.toString(),
+                               "CONSTANT_Class_info", i);
+        }
+        int nameIndex =  poolIdx[getChar(index + 1)];
+        int len = getChar(nameIndex + 1);
+        int start = nameIndex + 3;
+        if (buf[start] == '[' || buf[start + len - 1] == ';')
+            throw badClassFile("wrong class name"); //TODO: proper diagnostics
+        return names.fromUtf(internalize(buf, start, len));
+    }
+
+    /** Read name.
+     */
+    Name readName(int i) {
+        Object obj = readPool(i);
+        if (obj != null && !(obj instanceof Name))
+            throw badClassFile("bad.const.pool.entry",
+                               currentClassFile.toString(),
+                               "CONSTANT_Utf8_info or CONSTANT_String_info", i);
+        return (Name)obj;
+    }
+
+    /** Read name and type.
+     */
+    NameAndType readNameAndType(int i) {
+        Object obj = readPool(i);
+        if (obj != null && !(obj instanceof NameAndType))
+            throw badClassFile("bad.const.pool.entry",
+                               currentClassFile.toString(),
+                               "CONSTANT_NameAndType_info", i);
+        return (NameAndType)obj;
+    }
+
+    /** Read the name of a module.
+     * The name is stored in a CONSTANT_Module entry, in
+     * JVMS 4.2 binary form (using ".", not "/")
+     */
+    Name readModuleName(int i) {
+        return readName(i);
+    }
+
     /** Read module_flags.
      */
     Set<ModuleFlags> readModuleFlags(int flags) {
         Set<ModuleFlags> set = EnumSet.noneOf(ModuleFlags.class);
         for (ModuleFlags f : ModuleFlags.values()) {

@@ -486,11 +760,11 @@
         case '(':
             sigp++;
             List<Type> argtypes = sigToTypes(')');
             Type restype = sigToType();
             List<Type> thrown = List.nil();
-            while (sigp < siglimit && signature[sigp] == '^') {
+            while (signature[sigp] == '^') {
                 sigp++;
                 thrown = thrown.prepend(sigToType());
             }
             // if there is a typevar in the throws clause we should state it.
             for (List<Type> l = thrown; l.nonEmpty(); l = l.tail) {

@@ -579,11 +853,11 @@
                             throw new UnsupportedOperationException();
                         }
                     };
                 switch (signature[sigp++]) {
                 case ';':
-                    if (sigp < siglimit && signature[sigp] == '.') {
+                    if (sigp < signature.length && signature[sigp] == '.') {
                         // support old-style GJC signatures
                         // The signature produced was
                         // Lfoo/Outer<Lfoo/X;>;.Lfoo/Outer$Inner<Lfoo/Y;>;
                         // rather than say
                         // Lfoo/Outer<Lfoo/X;>.Inner<Lfoo/Y;>;

@@ -773,20 +1047,20 @@
         AttributeReader[] readers = {
             // v45.3 attributes
 
             new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
                 protected void read(Symbol sym, int attrLen) {
-                    if (saveParameterNames)
+                    if (readAllOfClassFile || saveParameterNames)
                         ((MethodSymbol)sym).code = readCode(sym);
                     else
                         bp = bp + attrLen;
                 }
             },
 
             new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) {
                 protected void read(Symbol sym, int attrLen) {
-                    Object v = poolReader.getConstant(nextChar());
+                    Object v = readPool(nextChar());
                     // Ignore ConstantValue attribute if field not final.
                     if ((sym.flags() & FINAL) == 0) {
                         return;
                     }
                     VarSymbol var = (VarSymbol) sym;

@@ -839,11 +1113,11 @@
             new AttributeReader(names.Exceptions, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
                 protected void read(Symbol sym, int attrLen) {
                     int nexceptions = nextChar();
                     List<Type> thrown = List.nil();
                     for (int j = 0; j < nexceptions; j++)
-                        thrown = thrown.prepend(poolReader.getClass(nextChar()).type);
+                        thrown = thrown.prepend(readClassSymbol(nextChar()).type);
                     if (sym.type.getThrownTypes().isEmpty())
                         sym.type.asMethodType().thrown = thrown.reverse();
                 }
             },
 

@@ -897,11 +1171,11 @@
             },
 
             new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
                 protected void read(Symbol sym, int attrLen) {
                     ClassSymbol c = (ClassSymbol) sym;
-                    Name n = poolReader.getName(nextChar());
+                    Name n = readName(nextChar());
                     c.sourcefile = new SourceFileObject(n);
                     // If the class is a toplevel class, originating from a Java source file,
                     // but the class name does not match the file name, then it is
                     // an auxiliary class.
                     String sn = n.toString();

@@ -935,22 +1209,21 @@
                         ClassSymbol c = (ClassSymbol) sym;
                         readingClassAttr = true;
                         try {
                             ClassType ct1 = (ClassType)c.type;
                             Assert.check(c == currentOwner);
-                            ct1.typarams_field = poolReader.getName(nextChar())
-                                    .map(ClassReader.this::sigToTypeParams);
+                            ct1.typarams_field = readTypeParams(nextChar());
                             ct1.supertype_field = sigToType();
                             ListBuffer<Type> is = new ListBuffer<>();
                             while (sigp != siglimit) is.append(sigToType());
                             ct1.interfaces_field = is.toList();
                         } finally {
                             readingClassAttr = false;
                         }
                     } else {
                         List<Type> thrown = sym.type.getThrownTypes();
-                        sym.type = poolReader.getType(nextChar());
+                        sym.type = readType(nextChar());
                         //- System.err.println(" # " + sym.type);
                         if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
                             sym.type.asMethodType().thrown = thrown;
 
                     }

@@ -1067,23 +1340,23 @@
                 protected void read(Symbol sym, int attrLen) {
                     if (sym.kind == TYP && sym.owner.kind == MDL) {
                         ModuleSymbol msym = (ModuleSymbol) sym.owner;
                         ListBuffer<Directive> directives = new ListBuffer<>();
 
-                        Name moduleName = poolReader.peekModuleName(nextChar(), names::fromUtf);
+                        Name moduleName = readModuleName(nextChar());
                         if (currentModule.name != moduleName) {
                             throw badClassFile("module.name.mismatch", moduleName, currentModule.name);
                         }
 
                         Set<ModuleFlags> moduleFlags = readModuleFlags(nextChar());
                         msym.flags.addAll(moduleFlags);
-                        msym.version = optPoolEntry(nextChar(), poolReader::getName, null);
+                        msym.version = readName(nextChar());
 
                         ListBuffer<RequiresDirective> requires = new ListBuffer<>();
                         int nrequires = nextChar();
                         for (int i = 0; i < nrequires; i++) {
-                            ModuleSymbol rsym = poolReader.getModule(nextChar());
+                            ModuleSymbol rsym = syms.enterModule(readModuleName(nextChar()));
                             Set<RequiresFlag> flags = readRequiresFlags(nextChar());
                             if (rsym == syms.java_base && majorVersion >= V54.major) {
                                 if (flags.contains(RequiresFlag.TRANSITIVE)) {
                                     throw badClassFile("bad.requires.flag", RequiresFlag.TRANSITIVE);
                                 }

@@ -1098,20 +1371,21 @@
                         directives.addAll(msym.requires);
 
                         ListBuffer<ExportsDirective> exports = new ListBuffer<>();
                         int nexports = nextChar();
                         for (int i = 0; i < nexports; i++) {
-                            PackageSymbol p = poolReader.getPackage(nextChar());
+                            Name n = readName(nextChar());
+                            PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n)));
                             Set<ExportsFlag> flags = readExportsFlags(nextChar());
                             int nto = nextChar();
                             List<ModuleSymbol> to;
                             if (nto == 0) {
                                 to = null;
                             } else {
                                 ListBuffer<ModuleSymbol> lb = new ListBuffer<>();
                                 for (int t = 0; t < nto; t++)
-                                    lb.append(poolReader.getModule(nextChar()));
+                                    lb.append(syms.enterModule(readModuleName(nextChar())));
                                 to = lb.toList();
                             }
                             exports.add(new ExportsDirective(p, to, flags));
                         }
                         msym.exports = exports.toList();

@@ -1120,20 +1394,21 @@
                         int nopens = nextChar();
                         if (nopens != 0 && msym.flags.contains(ModuleFlags.OPEN)) {
                             throw badClassFile("module.non.zero.opens", currentModule.name);
                         }
                         for (int i = 0; i < nopens; i++) {
-                            PackageSymbol p = poolReader.getPackage(nextChar());
+                            Name n = readName(nextChar());
+                            PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n)));
                             Set<OpensFlag> flags = readOpensFlags(nextChar());
                             int nto = nextChar();
                             List<ModuleSymbol> to;
                             if (nto == 0) {
                                 to = null;
                             } else {
                                 ListBuffer<ModuleSymbol> lb = new ListBuffer<>();
                                 for (int t = 0; t < nto; t++)
-                                    lb.append(poolReader.getModule(nextChar()));
+                                    lb.append(syms.enterModule(readModuleName(nextChar())));
                                 to = lb.toList();
                             }
                             opens.add(new OpensDirective(p, to, flags));
                         }
                         msym.opens = opens.toList();

@@ -1142,33 +1417,29 @@
                         msym.directives = directives.toList();
 
                         ListBuffer<InterimUsesDirective> uses = new ListBuffer<>();
                         int nuses = nextChar();
                         for (int i = 0; i < nuses; i++) {
-                            Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper);
+                            Name srvc = readClassName(nextChar());
                             uses.add(new InterimUsesDirective(srvc));
                         }
                         interimUses = uses.toList();
 
                         ListBuffer<InterimProvidesDirective> provides = new ListBuffer<>();
                         int nprovides = nextChar();
                         for (int p = 0; p < nprovides; p++) {
-                            Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper);
+                            Name srvc = readClassName(nextChar());
                             int nimpls = nextChar();
                             ListBuffer<Name> impls = new ListBuffer<>();
                             for (int i = 0; i < nimpls; i++) {
-                                impls.append(poolReader.peekClassName(nextChar(), this::classNameMapper));
+                                impls.append(readClassName(nextChar()));
                             provides.add(new InterimProvidesDirective(srvc, impls.toList()));
                             }
                         }
                         interimProvides = provides.toList();
                     }
                 }
-
-                private Name classNameMapper(byte[] arr, int offset, int length) {
-                    return names.fromUtf(ClassFile.internalize(arr, offset, length));
-                }
             },
 
             new AttributeReader(names.ModuleResolution, V53, CLASS_ATTRIBUTE) {
                 @Override
                 protected boolean accepts(AttributeKind kind) {

@@ -1191,12 +1462,12 @@
         // sym is a nested class with an "Enclosing Method" attribute
         // remove sym from it's current owners scope and place it in
         // the scope specified by the attribute
         sym.owner.members().remove(sym);
         ClassSymbol self = (ClassSymbol)sym;
-        ClassSymbol c = poolReader.getClass(nextChar());
-        NameAndType nt = optPoolEntry(nextChar(), poolReader::getNameAndType, null);
+        ClassSymbol c = readClassSymbol(nextChar());
+        NameAndType nt = readNameAndType(nextChar());
 
         if (c.members_field == null || c.kind != TYP)
             throw badClassFile("bad.enclosing.class", self, c);
 
         MethodSymbol m = findMethod(nt, c.members_field, self.flags());

@@ -1229,14 +1500,10 @@
         }
     }
 
     // See java.lang.Class
     private Name simpleBinaryName(Name self, Name enclosing) {
-        if (!self.startsWith(enclosing)) {
-            throw badClassFile("bad.enclosing.method", self);
-        }
-
         String simpleBinaryName = self.toString().substring(enclosing.toString().length());
         if (simpleBinaryName.length() < 1 || simpleBinaryName.charAt(0) != '$')
             throw badClassFile("bad.enclosing.method", self);
         int index = 1;
         while (index < simpleBinaryName.length() &&

@@ -1247,11 +1514,11 @@
 
     private MethodSymbol findMethod(NameAndType nt, Scope scope, long flags) {
         if (nt == null)
             return null;
 
-        MethodType type = nt.type.asMethodType();
+        MethodType type = nt.uniqueType.type.asMethodType();
 
         for (Symbol sym : scope.getSymbolsByName(nt.name)) {
             if (sym.kind == MTH && isSameBinaryType(sym.type.asMethodType(), type))
                 return (MethodSymbol)sym;
         }

@@ -1260,19 +1527,19 @@
             // not a constructor
             return null;
         if ((flags & INTERFACE) != 0)
             // no enclosing instance
             return null;
-        if (nt.type.getParameterTypes().isEmpty())
+        if (nt.uniqueType.type.getParameterTypes().isEmpty())
             // no parameters
             return null;
 
         // A constructor of an inner class.
         // Remove the first argument (the enclosing instance)
-        nt = new NameAndType(nt.name, new MethodType(nt.type.getParameterTypes().tail,
-                                 nt.type.getReturnType(),
-                                 nt.type.getThrownTypes(),
+        nt.setType(new MethodType(nt.uniqueType.type.getParameterTypes().tail,
+                                 nt.uniqueType.type.getReturnType(),
+                                 nt.uniqueType.type.getThrownTypes(),
                                  syms.methodClass));
         // Try searching again
         return findMethod(nt, scope, flags);
     }
 

@@ -1305,11 +1572,11 @@
     }
 
     void readAttrs(Symbol sym, AttributeKind kind) {
         char ac = nextChar();
         for (int i = 0; i < ac; i++) {
-            Name attrName = poolReader.getName(nextChar());
+            Name attrName = readName(nextChar());
             int attrLen = nextInt();
             AttributeReader r = attributeReaders.get(attrName);
             if (r != null && r.accepts(kind))
                 r.read(sym, attrLen);
             else  {

@@ -1408,11 +1675,11 @@
     }
 
     /** Read parameter annotations.
      */
     void readParameterAnnotations(Symbol meth) {
-        int numParameters = buf.getByte(bp++) & 0xFF;
+        int numParameters = buf[bp++] & 0xFF;
         if (parameterAnnotations == null) {
             parameterAnnotations = new ParameterAnnotations[numParameters];
         } else if (parameterAnnotations.length != numParameters) {
             throw badClassFile("bad.runtime.invisible.param.annotations", meth);
         }

@@ -1452,34 +1719,43 @@
         annotate.normal(new AnnotationDefaultCompleter(meth, value));
     }
 
     Type readTypeOrClassSymbol(int i) {
         // support preliminary jsr175-format class files
-        if (poolReader.hasTag(i, CONSTANT_Class))
-            return poolReader.getClass(i).type;
+        if (buf[poolIdx[i]] == CONSTANT_Class)
+            return readClassSymbol(i).type;
+        return readTypeToProxy(i);
+    }
+    Type readEnumType(int i) {
+        // support preliminary jsr175-format class files
+        int index = poolIdx[i];
+        int length = getChar(index + 1);
+        if (buf[index + length + 2] != ';')
+            return enterClass(readName(i)).type;
         return readTypeToProxy(i);
     }
     Type readTypeToProxy(int i) {
         if (currentModule.module_info == currentOwner) {
-            return new ProxyType(i);
+            int index = poolIdx[i];
+            return new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1)));
         } else {
-            return poolReader.getType(i);
+            return readType(i);
         }
     }
 
     CompoundAnnotationProxy readCompoundAnnotation() {
         Type t;
         if (currentModule.module_info == currentOwner) {
-            int cpIndex = nextChar();
-            t = new ProxyType(cpIndex);
+            int index = poolIdx[nextChar()];
+            t = new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1)));
         } else {
             t = readTypeOrClassSymbol(nextChar());
         }
         int numFields = nextChar();
         ListBuffer<Pair<Name,Attribute>> pairs = new ListBuffer<>();
         for (int i=0; i<numFields; i++) {
-            Name name = poolReader.getName(nextChar());
+            Name name = readName(nextChar());
             Attribute value = readAttributeValue();
             pairs.append(new Pair<>(name, value));
         }
         return new CompoundAnnotationProxy(t, pairs.toList());
     }

@@ -1688,44 +1964,33 @@
 
         return TypeAnnotationPosition.getTypePathFromBinary(loc.toList());
 
     }
 
-    /**
-     * Helper function to read an optional pool entry (with given function); this is used while parsing
-     * InnerClasses and EnclosingMethod attributes, as well as when parsing supertype descriptor,
-     * as per JVMS.
-     */
-    <Z> Z optPoolEntry(int index, IntFunction<Z> poolFunc, Z defaultValue) {
-        return (index == 0) ?
-                defaultValue :
-                poolFunc.apply(index);
-    }
-
     Attribute readAttributeValue() {
-        char c = (char) buf.getByte(bp++);
+        char c = (char) buf[bp++];
         switch (c) {
         case 'B':
-            return new Attribute.Constant(syms.byteType, poolReader.getConstant(nextChar()));
+            return new Attribute.Constant(syms.byteType, readPool(nextChar()));
         case 'C':
-            return new Attribute.Constant(syms.charType, poolReader.getConstant(nextChar()));
+            return new Attribute.Constant(syms.charType, readPool(nextChar()));
         case 'D':
-            return new Attribute.Constant(syms.doubleType, poolReader.getConstant(nextChar()));
+            return new Attribute.Constant(syms.doubleType, readPool(nextChar()));
         case 'F':
-            return new Attribute.Constant(syms.floatType, poolReader.getConstant(nextChar()));
+            return new Attribute.Constant(syms.floatType, readPool(nextChar()));
         case 'I':
-            return new Attribute.Constant(syms.intType, poolReader.getConstant(nextChar()));
+            return new Attribute.Constant(syms.intType, readPool(nextChar()));
         case 'J':
-            return new Attribute.Constant(syms.longType, poolReader.getConstant(nextChar()));
+            return new Attribute.Constant(syms.longType, readPool(nextChar()));
         case 'S':
-            return new Attribute.Constant(syms.shortType, poolReader.getConstant(nextChar()));
+            return new Attribute.Constant(syms.shortType, readPool(nextChar()));
         case 'Z':
-            return new Attribute.Constant(syms.booleanType, poolReader.getConstant(nextChar()));
+            return new Attribute.Constant(syms.booleanType, readPool(nextChar()));
         case 's':
-            return new Attribute.Constant(syms.stringType, poolReader.getName(nextChar()).toString());
+            return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString());
         case 'e':
-            return new EnumAttributeProxy(readTypeToProxy(nextChar()), poolReader.getName(nextChar()));
+            return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar()));
         case 'c':
             return new ClassAttributeProxy(readTypeOrClassSymbol(nextChar()));
         case '[': {
             int n = nextChar();
             ListBuffer<Attribute> l = new ListBuffer<>();

@@ -2130,23 +2395,23 @@
 
     /** Read a field.
      */
     VarSymbol readField() {
         long flags = adjustFieldFlags(nextChar());
-        Name name = poolReader.getName(nextChar());
-        Type type = poolReader.getType(nextChar());
+        Name name = readName(nextChar());
+        Type type = readType(nextChar());
         VarSymbol v = new VarSymbol(flags, name, type, currentOwner);
         readMemberAttrs(v);
         return v;
     }
 
     /** Read a method.
      */
     MethodSymbol readMethod() {
         long flags = adjustMethodFlags(nextChar());
-        Name name = poolReader.getName(nextChar());
-        Type type = poolReader.getType(nextChar());
+        Name name = readName(nextChar());
+        Type type = readType(nextChar());
         if (currentOwner.isInterface() &&
                 (flags & ABSTRACT) == 0 && !name.equals(names.clinit)) {
             if (majorVersion > Version.V52.major ||
                     (majorVersion == Version.V52.major && minorVersion >= Version.V52.minor)) {
                 if ((flags & (STATIC | PRIVATE)) == 0) {

@@ -2286,16 +2551,18 @@
                 int skip = Code.width(jvmType.getParameterTypes())
                         - Code.width(sym.type.getParameterTypes());
                 firstParam += skip;
             }
         }
-        Set<Name> paramNames = new HashSet<>();
+        List<Name> paramNames = List.nil();
         ListBuffer<VarSymbol> params = new ListBuffer<>();
         int nameIndex = firstParam;
         int annotationIndex = 0;
         for (Type t: sym.type.getParameterTypes()) {
-            VarSymbol param = parameter(nameIndex, t, sym, paramNames);
+            Name name = parameterName(nameIndex, paramNames);
+            paramNames = paramNames.prepend(name);
+            VarSymbol param = new VarSymbol(PARAMETER, name, t, sym);
             params.append(param);
             if (parameterAnnotations != null) {
                 ParameterAnnotations annotations = parameterAnnotations[annotationIndex];
                 if (annotations != null && annotations.proxies != null
                         && !annotations.proxies.isEmpty()) {

@@ -2316,28 +2583,22 @@
 
 
     // Returns the name for the parameter at position 'index', either using
     // names read from the MethodParameters, or by synthesizing a name that
     // is not on the 'exclude' list.
-    private VarSymbol parameter(int index, Type t, MethodSymbol owner, Set<Name> exclude) {
-        long flags = PARAMETER;
-        Name argName;
+    private Name parameterName(int index, List<Name> exclude) {
         if (parameterNameIndices != null && index < parameterNameIndices.length
                 && parameterNameIndices[index] != 0) {
-            argName = optPoolEntry(parameterNameIndices[index], poolReader::getName, names.empty);
-            flags |= NAME_FILLED;
-        } else {
-            String prefix = "arg";
-            while (true) {
-                argName = names.fromString(prefix + exclude.size());
-                if (!exclude.contains(argName))
-                    break;
-                prefix += "$";
-            }
+            return readName(parameterNameIndices[index]);
+        }
+        String prefix = "arg";
+        while (true) {
+            Name argName = names.fromString(prefix + exclude.size());
+            if (!exclude.contains(argName))
+                return argName;
+            prefix += "$";
         }
-        exclude.add(argName);
-        return new ParamSymbol(flags, argName, t, owner);
     }
 
     /**
      * skip n bytes
      */

@@ -2410,11 +2671,11 @@
         long flags = adjustClassFlags(f);
         if ((flags & MODULE) == 0) {
             if (c.owner.kind == PCK || c.owner.kind == ERR) c.flags_field = flags;
             // read own class name and check that it matches
             currentModule = c.packge().modle;
-            ClassSymbol self = poolReader.getClass(nextChar());
+            ClassSymbol self = readClassSymbol(nextChar());
             if (c != self) {
                 throw badClassFile("class.file.wrong.class",
                                    self.flatname);
             }
         } else {

@@ -2439,23 +2700,29 @@
         for (int i = 0; i < fieldCount; i++) skipMember();
         char methodCount = nextChar();
         for (int i = 0; i < methodCount; i++) skipMember();
         readClassAttrs(c);
 
+        if (readAllOfClassFile) {
+            for (int i = 1; i < poolObj.length; i++) readPool(i);
+            c.pool = new Pool(poolObj.length, poolObj, types);
+        }
+
         // reset and read rest of classinfo
         bp = startbp;
         int n = nextChar();
         if ((flags & MODULE) != 0 && n > 0) {
             throw badClassFile("module.info.invalid.super.class");
         }
         if (ct.supertype_field == null)
-            ct.supertype_field =
-                    optPoolEntry(n, idx -> poolReader.getClass(idx).erasure(types), Type.noType);
+            ct.supertype_field = (n == 0)
+                ? Type.noType
+                : readClassSymbol(n).erasure(types);
         n = nextChar();
         List<Type> is = List.nil();
         for (int i = 0; i < n; i++) {
-            Type _inter = poolReader.getClass(nextChar()).erasure(types);
+            Type _inter = readClassSymbol(nextChar()).erasure(types);
             is = is.prepend(_inter);
         }
         if (ct.interfaces_field == null)
             ct.interfaces_field = is.reverse();
 

@@ -2472,14 +2739,12 @@
      */
     void readInnerClasses(ClassSymbol c) {
         int n = nextChar();
         for (int i = 0; i < n; i++) {
             nextChar(); // skip inner class symbol
-            int outerIdx = nextChar();
-            int nameIdx = nextChar();
-            ClassSymbol outer = optPoolEntry(outerIdx, poolReader::getClass, null);
-            Name name = optPoolEntry(nameIdx, poolReader::getName, names.empty);
+            ClassSymbol outer = readClassSymbol(nextChar());
+            Name name = readName(nextChar());
             if (name == null) name = names.empty;
             long flags = adjustClassFlags(nextChar());
             if (outer != null) { // we have a member class
                 if (name == names.empty)
                     name = names.one;

@@ -2529,12 +2794,11 @@
             } else {
                 preview.warnPreview(c.classfile, majorVersion);
             }
         }
 
-        poolReader = new PoolReader(this, names, syms);
-        bp = poolReader.readPool(buf, bp);
+        indexPool();
         if (signatureBuffer.length < bp) {
             int ns = Integer.highestOneBit(bp) << 1;
             signatureBuffer = new byte[ns];
         }
         readClass(c);

@@ -2547,12 +2811,11 @@
         filling = true;
         target = null;
         repeatable = null;
         try {
             bp = 0;
-            buf.reset();
-            buf.appendStream(c.classfile.openInputStream());
+            buf = readInputStream(buf, c.classfile.openInputStream());
             readClassBuffer(c);
             if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) {
                 List<Type> missing = missingTypeVariables;
                 List<Type> found = foundTypeVariables;
                 missingTypeVariables = List.nil();

@@ -2602,10 +2865,47 @@
             missingTypeVariables = List.nil();
             foundTypeVariables = List.nil();
             filling = false;
         }
     }
+    // where
+        private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
+            try {
+                buf = ensureCapacity(buf, s.available());
+                int r = s.read(buf);
+                int bp = 0;
+                while (r != -1) {
+                    bp += r;
+                    buf = ensureCapacity(buf, bp);
+                    r = s.read(buf, bp, buf.length - bp);
+                }
+                return buf;
+            } finally {
+                try {
+                    s.close();
+                } catch (IOException e) {
+                    /* Ignore any errors, as this stream may have already
+                     * thrown a related exception which is the one that
+                     * should be reported.
+                     */
+                }
+            }
+        }
+        /*
+         * ensureCapacity will increase the buffer as needed, taking note that
+         * the new buffer will always be greater than the needed and never
+         * exactly equal to the needed size or bp. If equal then the read (above)
+         * will infinitely loop as buf.length - bp == 0.
+         */
+        private static byte[] ensureCapacity(byte[] buf, int needed) {
+            if (buf.length <= needed) {
+                byte[] old = buf;
+                buf = new byte[Integer.highestOneBit(needed) << 1];
+                System.arraycopy(old, 0, buf, 0, old.length);
+            }
+            return buf;
+        }
 
     /** We can only read a single class file at a time; this
      *  flag keeps track of when we are currently reading a class
      *  file.
      */

@@ -2788,15 +3088,15 @@
         }
     }
 
     private class ProxyType extends Type {
 
-        private final Name name;
+        private final byte[] content;
 
-        public ProxyType(int index) {
+        public ProxyType(byte[] content) {
             super(syms.noSymbol, TypeMetadata.EMPTY);
-            this.name = poolReader.getName(index);
+            this.content = content;
         }
 
         @Override
         public TypeTag getTag() {
             return TypeTag.NONE;

@@ -2806,11 +3106,11 @@
         public Type cloneWithMetadata(TypeMetadata metadata) {
             throw new UnsupportedOperationException();
         }
 
         public Type resolve() {
-            return name.map(ClassReader.this::sigToType);
+            return sigToType(content, 0, content.length);
         }
 
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
         public String toString() {
             return "<ProxyType>";
< prev index next >