< prev index next >

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

Print this page

        

*** 34,44 **** 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; --- 34,43 ----
*** 54,65 **** 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.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; --- 53,64 ---- 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.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,108 **** --- 98,112 ---- /** 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,182 **** */ protected ModuleSymbol currentModule = null; /** The buffer containing the currently read class file. */ ! ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE); /** The current input pointer. */ protected int bp; ! /** The pool reader. */ ! PoolReader poolReader; /** The major version number of the class file being read. */ int majorVersion; /** The minor version number of the class file being read. */ int minorVersion; --- 168,191 ---- */ protected ModuleSymbol currentModule = null; /** The buffer containing the currently read class file. */ ! byte[] buf = new byte[INITIAL_BUFFER_SIZE]; /** The current input pointer. */ protected int bp; ! /** 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. */ ! 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,344 **** ***********************************************************************/ /** Read a character. */ char nextChar() { ! char res = buf.getChar(bp); ! bp += 2; ! return res; } /** Read a byte. */ int nextByte() { ! return buf.getByte(bp++) & 0xFF; } /** Read an integer. */ int nextInt() { ! int res = buf.getInt(bp); ! bp += 4; ! return res; } /************************************************************************ * Constant Pool Access ***********************************************************************/ /** Read module_flags. */ Set<ModuleFlags> readModuleFlags(int flags) { Set<ModuleFlags> set = EnumSet.noneOf(ModuleFlags.class); for (ModuleFlags f : ModuleFlags.values()) { --- 321,618 ---- ***********************************************************************/ /** Read a character. */ char nextChar() { ! return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF)); } /** Read a byte. */ int nextByte() { ! return buf[bp++] & 0xFF; } /** Read an integer. */ int nextInt() { ! 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,496 **** case '(': sigp++; List<Type> argtypes = sigToTypes(')'); Type restype = sigToType(); List<Type> thrown = List.nil(); ! while (sigp < siglimit && 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) { --- 760,770 ---- case '(': sigp++; List<Type> argtypes = sigToTypes(')'); Type restype = sigToType(); List<Type> thrown = List.nil(); ! 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,589 **** throw new UnsupportedOperationException(); } }; switch (signature[sigp++]) { case ';': ! if (sigp < siglimit && 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;>; --- 853,863 ---- throw new UnsupportedOperationException(); } }; switch (signature[sigp++]) { case ';': ! 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,792 **** AttributeReader[] readers = { // v45.3 attributes new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) { protected void read(Symbol sym, int attrLen) { ! if (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()); // Ignore ConstantValue attribute if field not final. if ((sym.flags() & FINAL) == 0) { return; } VarSymbol var = (VarSymbol) sym; --- 1047,1066 ---- AttributeReader[] readers = { // v45.3 attributes new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) { protected 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) { protected void read(Symbol sym, int attrLen) { ! Object v = readPool(nextChar()); // Ignore ConstantValue attribute if field not final. if ((sym.flags() & FINAL) == 0) { return; } VarSymbol var = (VarSymbol) sym;
*** 839,849 **** 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); if (sym.type.getThrownTypes().isEmpty()) sym.type.asMethodType().thrown = thrown.reverse(); } }, --- 1113,1123 ---- 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(readClassSymbol(nextChar()).type); if (sym.type.getThrownTypes().isEmpty()) sym.type.asMethodType().thrown = thrown.reverse(); } },
*** 897,907 **** }, new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) { protected void read(Symbol sym, int attrLen) { ClassSymbol c = (ClassSymbol) sym; ! Name n = poolReader.getName(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(); --- 1171,1181 ---- }, new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) { protected void read(Symbol sym, int attrLen) { ClassSymbol c = (ClassSymbol) sym; ! 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,956 **** 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.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()); //- System.err.println(" # " + sym.type); if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty()) sym.type.asMethodType().thrown = thrown; } --- 1209,1229 ---- ClassSymbol c = (ClassSymbol) sym; readingClassAttr = true; try { ClassType ct1 = (ClassType)c.type; Assert.check(c == currentOwner); ! 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 = readType(nextChar()); //- System.err.println(" # " + sym.type); if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty()) sym.type.asMethodType().thrown = thrown; }
*** 1067,1089 **** 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); 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); ListBuffer<RequiresDirective> requires = new ListBuffer<>(); int nrequires = nextChar(); for (int i = 0; i < nrequires; i++) { ! ModuleSymbol rsym = poolReader.getModule(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); } --- 1340,1362 ---- 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 = 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 = readName(nextChar()); ListBuffer<RequiresDirective> requires = new ListBuffer<>(); int nrequires = nextChar(); for (int i = 0; i < nrequires; i++) { ! 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,1117 **** directives.addAll(msym.requires); ListBuffer<ExportsDirective> exports = new ListBuffer<>(); int nexports = nextChar(); for (int i = 0; i < nexports; i++) { ! PackageSymbol p = poolReader.getPackage(nextChar()); 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())); to = lb.toList(); } exports.add(new ExportsDirective(p, to, flags)); } msym.exports = exports.toList(); --- 1371,1391 ---- directives.addAll(msym.requires); ListBuffer<ExportsDirective> exports = new ListBuffer<>(); int nexports = nextChar(); for (int i = 0; i < nexports; i++) { ! 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(syms.enterModule(readModuleName(nextChar()))); to = lb.toList(); } exports.add(new ExportsDirective(p, to, flags)); } msym.exports = exports.toList();
*** 1120,1139 **** 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()); 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())); to = lb.toList(); } opens.add(new OpensDirective(p, to, flags)); } msym.opens = opens.toList(); --- 1394,1414 ---- 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++) { ! 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(syms.enterModule(readModuleName(nextChar()))); to = lb.toList(); } opens.add(new OpensDirective(p, to, flags)); } msym.opens = opens.toList();
*** 1142,1174 **** 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); 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); int nimpls = nextChar(); ListBuffer<Name> impls = new ListBuffer<>(); for (int i = 0; i < nimpls; i++) { ! impls.append(poolReader.peekClassName(nextChar(), this::classNameMapper)); 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) { --- 1417,1445 ---- msym.directives = directives.toList(); ListBuffer<InterimUsesDirective> uses = new ListBuffer<>(); int nuses = nextChar(); for (int i = 0; i < nuses; i++) { ! 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 = readClassName(nextChar()); int nimpls = nextChar(); ListBuffer<Name> impls = new ListBuffer<>(); for (int i = 0; i < nimpls; i++) { ! impls.append(readClassName(nextChar())); provides.add(new InterimProvidesDirective(srvc, impls.toList())); } } interimProvides = provides.toList(); } } }, new AttributeReader(names.ModuleResolution, V53, CLASS_ATTRIBUTE) { @Override protected boolean accepts(AttributeKind kind) {
*** 1191,1202 **** // 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); if (c.members_field == null || c.kind != TYP) throw badClassFile("bad.enclosing.class", self, c); MethodSymbol m = findMethod(nt, c.members_field, self.flags()); --- 1462,1473 ---- // 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 = 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,1242 **** } } // 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() && --- 1500,1509 ----
*** 1247,1257 **** private MethodSymbol findMethod(NameAndType nt, Scope scope, long flags) { if (nt == null) return null; ! MethodType type = nt.type.asMethodType(); for (Symbol sym : scope.getSymbolsByName(nt.name)) { if (sym.kind == MTH && isSameBinaryType(sym.type.asMethodType(), type)) return (MethodSymbol)sym; } --- 1514,1524 ---- private MethodSymbol findMethod(NameAndType nt, Scope scope, long flags) { if (nt == null) return null; ! 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,1278 **** // not a constructor return null; if ((flags & INTERFACE) != 0) // no enclosing instance return null; ! if (nt.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(), syms.methodClass)); // Try searching again return findMethod(nt, scope, flags); } --- 1527,1545 ---- // not a constructor return null; if ((flags & INTERFACE) != 0) // no enclosing instance return null; ! if (nt.uniqueType.type.getParameterTypes().isEmpty()) // no parameters return null; // A constructor of an inner class. // Remove the first argument (the enclosing instance) ! 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,1315 **** } void readAttrs(Symbol sym, AttributeKind kind) { char ac = nextChar(); for (int i = 0; i < ac; i++) { ! Name attrName = poolReader.getName(nextChar()); int attrLen = nextInt(); AttributeReader r = attributeReaders.get(attrName); if (r != null && r.accepts(kind)) r.read(sym, attrLen); else { --- 1572,1582 ---- } void readAttrs(Symbol sym, AttributeKind kind) { char ac = nextChar(); for (int i = 0; i < ac; i++) { ! Name attrName = readName(nextChar()); int attrLen = nextInt(); AttributeReader r = attributeReaders.get(attrName); if (r != null && r.accepts(kind)) r.read(sym, attrLen); else {
*** 1408,1418 **** } /** Read parameter annotations. */ void readParameterAnnotations(Symbol meth) { ! int numParameters = buf.getByte(bp++) & 0xFF; if (parameterAnnotations == null) { parameterAnnotations = new ParameterAnnotations[numParameters]; } else if (parameterAnnotations.length != numParameters) { throw badClassFile("bad.runtime.invisible.param.annotations", meth); } --- 1675,1685 ---- } /** Read parameter annotations. */ void readParameterAnnotations(Symbol meth) { ! 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,1485 **** 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; return readTypeToProxy(i); } Type readTypeToProxy(int i) { if (currentModule.module_info == currentOwner) { ! return new ProxyType(i); } else { ! return poolReader.getType(i); } } CompoundAnnotationProxy readCompoundAnnotation() { Type t; if (currentModule.module_info == currentOwner) { ! int cpIndex = nextChar(); ! t = new ProxyType(cpIndex); } 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()); Attribute value = readAttributeValue(); pairs.append(new Pair<>(name, value)); } return new CompoundAnnotationProxy(t, pairs.toList()); } --- 1719,1761 ---- annotate.normal(new AnnotationDefaultCompleter(meth, value)); } Type readTypeOrClassSymbol(int i) { // support preliminary jsr175-format class files ! 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) { ! int index = poolIdx[i]; ! return new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1))); } else { ! return readType(i); } } CompoundAnnotationProxy readCompoundAnnotation() { Type t; if (currentModule.module_info == currentOwner) { ! 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 = readName(nextChar()); Attribute value = readAttributeValue(); pairs.append(new Pair<>(name, value)); } return new CompoundAnnotationProxy(t, pairs.toList()); }
*** 1688,1731 **** 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++); switch (c) { case 'B': ! return new Attribute.Constant(syms.byteType, poolReader.getConstant(nextChar())); case 'C': ! return new Attribute.Constant(syms.charType, poolReader.getConstant(nextChar())); case 'D': ! return new Attribute.Constant(syms.doubleType, poolReader.getConstant(nextChar())); case 'F': ! return new Attribute.Constant(syms.floatType, poolReader.getConstant(nextChar())); case 'I': ! return new Attribute.Constant(syms.intType, poolReader.getConstant(nextChar())); case 'J': ! return new Attribute.Constant(syms.longType, poolReader.getConstant(nextChar())); case 'S': ! return new Attribute.Constant(syms.shortType, poolReader.getConstant(nextChar())); case 'Z': ! return new Attribute.Constant(syms.booleanType, poolReader.getConstant(nextChar())); case 's': ! return new Attribute.Constant(syms.stringType, poolReader.getName(nextChar()).toString()); case 'e': ! return new EnumAttributeProxy(readTypeToProxy(nextChar()), poolReader.getName(nextChar())); case 'c': return new ClassAttributeProxy(readTypeOrClassSymbol(nextChar())); case '[': { int n = nextChar(); ListBuffer<Attribute> l = new ListBuffer<>(); --- 1964,1996 ---- return TypeAnnotationPosition.getTypePathFromBinary(loc.toList()); } Attribute readAttributeValue() { ! char c = (char) buf[bp++]; switch (c) { case 'B': ! return new Attribute.Constant(syms.byteType, readPool(nextChar())); case 'C': ! return new Attribute.Constant(syms.charType, readPool(nextChar())); case 'D': ! return new Attribute.Constant(syms.doubleType, readPool(nextChar())); case 'F': ! return new Attribute.Constant(syms.floatType, readPool(nextChar())); case 'I': ! return new Attribute.Constant(syms.intType, readPool(nextChar())); case 'J': ! return new Attribute.Constant(syms.longType, readPool(nextChar())); case 'S': ! return new Attribute.Constant(syms.shortType, readPool(nextChar())); case 'Z': ! return new Attribute.Constant(syms.booleanType, readPool(nextChar())); case 's': ! return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString()); case 'e': ! return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar())); case 'c': return new ClassAttributeProxy(readTypeOrClassSymbol(nextChar())); case '[': { int n = nextChar(); ListBuffer<Attribute> l = new ListBuffer<>();
*** 2130,2152 **** /** Read a field. */ VarSymbol readField() { long flags = adjustFieldFlags(nextChar()); ! Name name = poolReader.getName(nextChar()); ! Type type = poolReader.getType(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()); 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) { --- 2395,2417 ---- /** Read a field. */ VarSymbol readField() { long flags = adjustFieldFlags(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 = 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,2301 **** int skip = Code.width(jvmType.getParameterTypes()) - Code.width(sym.type.getParameterTypes()); firstParam += skip; } } ! Set<Name> paramNames = new HashSet<>(); ListBuffer<VarSymbol> params = new ListBuffer<>(); int nameIndex = firstParam; int annotationIndex = 0; for (Type t: sym.type.getParameterTypes()) { ! VarSymbol param = parameter(nameIndex, t, sym, paramNames); params.append(param); if (parameterAnnotations != null) { ParameterAnnotations annotations = parameterAnnotations[annotationIndex]; if (annotations != null && annotations.proxies != null && !annotations.proxies.isEmpty()) { --- 2551,2568 ---- int skip = Code.width(jvmType.getParameterTypes()) - Code.width(sym.type.getParameterTypes()); firstParam += skip; } } ! List<Name> paramNames = List.nil(); ListBuffer<VarSymbol> params = new ListBuffer<>(); int nameIndex = firstParam; int annotationIndex = 0; for (Type t: sym.type.getParameterTypes()) { ! 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,2343 **** // 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; 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 += "$"; ! } } - exclude.add(argName); - return new ParamSymbol(flags, argName, t, owner); } /** * skip n bytes */ --- 2583,2604 ---- // 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 Name parameterName(int index, List<Name> exclude) { if (parameterNameIndices != null && index < parameterNameIndices.length && parameterNameIndices[index] != 0) { ! return readName(parameterNameIndices[index]); ! } ! String prefix = "arg"; ! while (true) { ! Name argName = names.fromString(prefix + exclude.size()); ! if (!exclude.contains(argName)) ! return argName; ! prefix += "$"; } } /** * skip n bytes */
*** 2410,2420 **** 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()); if (c != self) { throw badClassFile("class.file.wrong.class", self.flatname); } } else { --- 2671,2681 ---- 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 = readClassSymbol(nextChar()); if (c != self) { throw badClassFile("class.file.wrong.class", self.flatname); } } else {
*** 2439,2461 **** for (int i = 0; i < fieldCount; i++) skipMember(); char methodCount = nextChar(); for (int i = 0; i < methodCount; i++) skipMember(); readClassAttrs(c); // 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); n = nextChar(); List<Type> is = List.nil(); for (int i = 0; i < n; i++) { ! Type _inter = poolReader.getClass(nextChar()).erasure(types); is = is.prepend(_inter); } if (ct.interfaces_field == null) ct.interfaces_field = is.reverse(); --- 2700,2728 ---- 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 = (n == 0) ! ? Type.noType ! : readClassSymbol(n).erasure(types); n = nextChar(); List<Type> is = List.nil(); for (int i = 0; i < n; i++) { ! Type _inter = readClassSymbol(nextChar()).erasure(types); is = is.prepend(_inter); } if (ct.interfaces_field == null) ct.interfaces_field = is.reverse();
*** 2472,2485 **** */ 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); 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; --- 2739,2750 ---- */ void readInnerClasses(ClassSymbol c) { int n = nextChar(); for (int i = 0; i < n; i++) { nextChar(); // skip inner class symbol ! 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,2540 **** } else { preview.warnPreview(c.classfile, majorVersion); } } ! poolReader = new PoolReader(this, names, syms); ! bp = poolReader.readPool(buf, bp); if (signatureBuffer.length < bp) { int ns = Integer.highestOneBit(bp) << 1; signatureBuffer = new byte[ns]; } readClass(c); --- 2794,2804 ---- } else { preview.warnPreview(c.classfile, majorVersion); } } ! indexPool(); if (signatureBuffer.length < bp) { int ns = Integer.highestOneBit(bp) << 1; signatureBuffer = new byte[ns]; } readClass(c);
*** 2547,2558 **** filling = true; target = null; repeatable = null; try { bp = 0; ! buf.reset(); ! buf.appendStream(c.classfile.openInputStream()); readClassBuffer(c); if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) { List<Type> missing = missingTypeVariables; List<Type> found = foundTypeVariables; missingTypeVariables = List.nil(); --- 2811,2821 ---- filling = true; target = null; repeatable = null; try { bp = 0; ! 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,2611 **** --- 2865,2911 ---- 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,2802 **** } } private class ProxyType extends Type { ! private final Name name; ! public ProxyType(int index) { super(syms.noSymbol, TypeMetadata.EMPTY); ! this.name = poolReader.getName(index); } @Override public TypeTag getTag() { return TypeTag.NONE; --- 3088,3102 ---- } } private class ProxyType extends Type { ! private final byte[] content; ! public ProxyType(byte[] content) { super(syms.noSymbol, TypeMetadata.EMPTY); ! this.content = content; } @Override public TypeTag getTag() { return TypeTag.NONE;
*** 2806,2816 **** public Type cloneWithMetadata(TypeMetadata metadata) { throw new UnsupportedOperationException(); } public Type resolve() { ! return name.map(ClassReader.this::sigToType); } @Override @DefinedBy(Api.LANGUAGE_MODEL) public String toString() { return "<ProxyType>"; --- 3106,3116 ---- public Type cloneWithMetadata(TypeMetadata metadata) { throw new UnsupportedOperationException(); } public Type resolve() { ! return sigToType(content, 0, content.length); } @Override @DefinedBy(Api.LANGUAGE_MODEL) public String toString() { return "<ProxyType>";
< prev index next >