--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Tue Mar 15 13:48:30 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Mar 17 19:04:28 2016 +0000
@@ -44,6 +44,7 @@
import com.sun.tools.javac.comp.Annotate;
import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Directive.*;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
@@ -100,6 +101,10 @@
*/
boolean allowSimplifiedVarargs;
+ /** Switch: allow modules.
+ */
+ boolean allowModules;
+
/** Lint option: warn about classfile issues
*/
boolean lintClassfile;
@@ -137,6 +142,9 @@
*/
protected WriteableScope typevars;
+ private List<InterimUsesDirective> interimUses = List.nil();
+ private List<InterimProvidesDirective> interimProvides = List.nil();
+
/** The path name of the class file currently being read.
*/
protected JavaFileObject currentClassFile = null;
@@ -145,6 +153,10 @@
*/
protected Symbol currentOwner = null;
+ /** The module containing the class currently being read.
+ */
+ protected ModuleSymbol currentModule = null;
+
/** The buffer containing the currently read class file.
*/
byte[] buf = new byte[INITIAL_BUFFER_SIZE];
@@ -228,6 +240,7 @@
Source source = Source.instance(context);
allowSimplifiedVarargs = source.allowSimplifiedVarargs();
+ allowModules = source.allowModules();
saveParameterNames = options.isSet("save-parameter-names");
@@ -478,7 +491,7 @@
// simplified to (buf[start] == '[')
return (buf[start] == '[' || buf[start + len - 1] == ';')
? (Object)sigToType(buf, start, len)
- : (Object)syms.enterClass(names.fromUtf(internalize(buf, start,
+ : (Object)enterClass(names.fromUtf(internalize(buf, start,
len)));
}
@@ -500,6 +513,23 @@
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) {
@@ -522,6 +552,34 @@
return (NameAndType)obj;
}
+ /** Read the class name of a module-info.class file.
+ * The name is stored in a CONSTANT_Class entry, where the
+ * class name is of the form module-name.module-info.
+ */
+ Name readModuleInfoName(int i) {
+ int classIndex = poolIdx[i];
+ if (buf[classIndex] == CONSTANT_Class) {
+ int utf8Index = poolIdx[getChar(classIndex + 1)];
+ if (buf[utf8Index] == CONSTANT_Utf8) {
+ int len = getChar(utf8Index + 1);
+ int start = utf8Index + 3;
+ return names.fromUtf(internalize(buf, start, len));
+ }
+ }
+ throw badClassFile("bad.module-info.name");
+ }
+
+ /** Read requires_flags.
+ */
+ Set<RequiresFlag> readRequiresFlags(int flags) {
+ Set<RequiresFlag> set = EnumSet.noneOf(RequiresFlag.class);
+ for (RequiresFlag f: RequiresFlag.values()) {
+ if ((flags & f.value) != 0)
+ set.add(f);
+ }
+ return set;
+ }
+
/************************************************************************
* Reading Types
***********************************************************************/
@@ -660,7 +718,7 @@
switch (c) {
case ';': { // end
- ClassSymbol t = syms.enterClass(names.fromUtf(signatureBuffer,
+ ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
@@ -674,7 +732,7 @@
}
case '<': // generic arguments
- ClassSymbol t = syms.enterClass(names.fromUtf(signatureBuffer,
+ ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
outer = new ClassType(outer, sigToTypes('>'), t) {
@@ -737,7 +795,7 @@
case '.':
//we have seen an enclosing non-generic class
if (outer != Type.noType) {
- t = syms.enterClass(names.fromUtf(signatureBuffer,
+ t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
outer = new ClassType(outer, List.<Type>nil(), t);
@@ -941,7 +999,12 @@
new AttributeReader(names.InnerClasses, V45_3, CLASS_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
ClassSymbol c = (ClassSymbol) sym;
- readInnerClasses(c);
+ if (currentModule.module_info == c) {
+ //prevent entering the classes too soon:
+ skipInnerClasses();
+ } else {
+ readInnerClasses(c);
+ }
}
},
@@ -981,25 +1044,6 @@
}
},
- new AttributeReader(names.MethodParameters, V52, MEMBER_ATTRIBUTE) {
- protected void read(Symbol sym, int attrlen) {
- int newbp = bp + attrlen;
- if (saveParameterNames) {
- sawMethodParameters = true;
- int numEntries = nextByte();
- parameterNameIndices = new int[numEntries];
- haveParameterNameIndices = true;
- for (int i = 0; i < numEntries; i++) {
- int nameIndex = nextChar();
- int flags = nextChar();
- parameterNameIndices[i] = nameIndex;
- }
- }
- bp = newbp;
- }
- },
-
-
new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
ClassSymbol c = (ClassSymbol) sym;
@@ -1130,12 +1174,109 @@
}
},
-
// The following attributes for a Code attribute are not currently handled
// StackMapTable
// SourceDebugExtension
// LineNumberTable
// LocalVariableTypeTable
+
+ // standard v52 attributes
+
+ new AttributeReader(names.MethodParameters, V52, MEMBER_ATTRIBUTE) {
+ protected void read(Symbol sym, int attrlen) {
+ int newbp = bp + attrlen;
+ if (saveParameterNames) {
+ sawMethodParameters = true;
+ int numEntries = nextByte();
+ parameterNameIndices = new int[numEntries];
+ haveParameterNameIndices = true;
+ for (int i = 0; i < numEntries; i++) {
+ int nameIndex = nextChar();
+ int flags = nextChar();
+ parameterNameIndices[i] = nameIndex;
+ }
+ }
+ bp = newbp;
+ }
+ },
+
+ // standard v53 attributes
+
+ new AttributeReader(names.Module, V53, CLASS_ATTRIBUTE) {
+ @Override
+ protected boolean accepts(AttributeKind kind) {
+ return super.accepts(kind) && allowModules;
+ }
+ 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<>();
+
+ ListBuffer<RequiresDirective> requires = new ListBuffer<>();
+ int nrequires = nextChar();
+ for (int i = 0; i < nrequires; i++) {
+ Name name = readName(nextChar());
+ ModuleSymbol rsym = syms.enterModule(name);
+ Set<RequiresFlag> flags = readRequiresFlags(nextChar());
+ requires.add(new RequiresDirective(rsym, flags));
+ }
+ msym.requires = requires.toList();
+ 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)));
+ 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(readName(nextChar())));
+ to = lb.toList();
+ }
+ exports.add(new ExportsDirective(p, to));
+ }
+ msym.exports = exports.toList();
+ directives.addAll(msym.exports);
+
+ 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 i = 0; i < nprovides; i++) {
+ Name srvc = readClassName(nextChar());
+ Name impl = readClassName(nextChar());
+ provides.add(new InterimProvidesDirective(srvc, impl));
+ }
+ interimProvides = provides.toList();
+ }
+ }
+ },
+
+ new AttributeReader(names.Version, V53, CLASS_ATTRIBUTE) {
+ @Override
+ protected boolean accepts(AttributeKind kind) {
+ return super.accepts(kind) && allowModules;
+ }
+ protected void read(Symbol sym, int attrLen) {
+ if (sym.kind == TYP && sym.owner.kind == MDL) {
+ ModuleSymbol msym = (ModuleSymbol) sym.owner;
+ msym.version = readName(nextChar());
+ }
+ }
+ },
};
for (AttributeReader r: readers)
@@ -1388,7 +1529,7 @@
int index = poolIdx[i];
int length = getChar(index + 1);
if (buf[index + length + 2] != ';')
- return syms.enterClass(readName(i)).type;
+ return enterClass(readName(i)).type;
return readType(i);
}
@@ -2175,6 +2316,16 @@
}
}
+ void skipInnerClasses() {
+ int n = nextChar();
+ for (int i = 0; i < n; i++) {
+ nextChar();
+ nextChar();
+ nextChar();
+ nextChar();
+ }
+ }
+
/** Enter type variables of this classtype and all enclosing ones in
* `typevars'.
*/
@@ -2193,6 +2344,14 @@
enterTypevars(sym.type);
}
+ protected ClassSymbol enterClass(Name name) {
+ return syms.enterClass(currentModule, name);
+ }
+
+ protected ClassSymbol enterClass(Name name, TypeSymbol owner) {
+ return syms.enterClass(currentModule, name, owner);
+ }
+
/** Read contents of a given class symbol `c'. Both external and internal
* versions of an inner class are read.
*/
@@ -2208,14 +2367,27 @@
enterTypevars(ct.getEnclosingType());
// read flags, or skip if this is an inner class
- long flags = adjustClassFlags(nextChar());
- if (c.owner.kind == PCK) c.flags_field = flags;
-
- // read own class name and check that it matches
- ClassSymbol self = readClassSymbol(nextChar());
- if (c != self)
- throw badClassFile("class.file.wrong.class",
- self.flatname);
+ long f = nextChar();
+ long flags = adjustClassFlags(f);
+ if ((flags & MODULE) == 0) {
+ if (c.owner.kind == PCK) 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 {
+ c.flags_field = flags;
+ Name modInfoName = readModuleInfoName(nextChar());
+ if (c.owner.name == null) {
+ syms.enterModule((ModuleSymbol) c.owner, Convert.packagePart(modInfoName));
+ } else {
+ // TODO: validate name
+ }
+ currentModule = (ModuleSymbol) c.owner;
+ }
// class attributes must be read before class
// skip ahead to read class attributes
@@ -2272,7 +2444,7 @@
if (outer != null) { // we have a member class
if (name == names.empty)
name = names.one;
- ClassSymbol member = syms.enterClass(name, outer);
+ ClassSymbol member = enterClass(name, outer);
if ((flags & STATIC) == 0) {
((ClassType)member.type).setEnclosingType(outer.type);
if (member.erasure_field != null)
@@ -2354,11 +2526,24 @@
} else {
c.setAnnotationTypeMetadata(AnnotationTypeMetadata.notAnAnnotationType());
}
+
+ if (c == currentModule.module_info) {
+ if (interimUses.nonEmpty() || interimProvides.nonEmpty()) {
+ Assert.check(currentModule.isCompleted());
+ currentModule.usesProvidesCompleter =
+ new UsesProvidesCompleter(currentModule, interimUses, interimProvides);
+ } else {
+ currentModule.uses = List.nil();
+ currentModule.provides = List.nil();
+ }
+ }
} catch (IOException ex) {
throw badClassFile("unable.to.access.file", ex.getMessage());
} catch (ArrayIndexOutOfBoundsException ex) {
throw badClassFile("bad.class.file", c.flatname);
} finally {
+ interimUses = List.nil();
+ interimProvides = List.nil();
missingTypeVariables = List.nil();
foundTypeVariables = List.nil();
filling = false;
@@ -2429,6 +2614,10 @@
}
long adjustClassFlags(long flags) {
+ if ((flags & ACC_MODULE) != 0) {
+ flags &= ~ACC_MODULE;
+ flags |= MODULE;
+ }
return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded
}
@@ -2580,4 +2769,58 @@
sym.getAnnotationTypeMetadata().setRepeatable(theRepeatable);
}
}
+
+ private static final class InterimUsesDirective {
+ public final Name service;
+
+ public InterimUsesDirective(Name service) {
+ this.service = service;
+ }
+
+ }
+
+ private static final class InterimProvidesDirective {
+ public final Name service;
+ public final Name impl;
+
+ public InterimProvidesDirective(Name service, Name impl) {
+ this.service = service;
+ this.impl = impl;
+ }
+
+ }
+
+ private final class UsesProvidesCompleter implements Completer {
+ private final ModuleSymbol currentModule;
+ private final List<InterimUsesDirective> interimUsesCopy;
+ private final List<InterimProvidesDirective> interimProvidesCopy;
+
+ public UsesProvidesCompleter(ModuleSymbol currentModule, List<InterimUsesDirective> interimUsesCopy, List<InterimProvidesDirective> interimProvidesCopy) {
+ this.currentModule = currentModule;
+ this.interimUsesCopy = interimUsesCopy;
+ this.interimProvidesCopy = interimProvidesCopy;
+ }
+
+ @Override
+ public void complete(Symbol sym) throws CompletionFailure {
+ ListBuffer<Directive> directives = new ListBuffer<>();
+ directives.addAll(currentModule.directives);
+ ListBuffer<UsesDirective> uses = new ListBuffer<>();
+ for (InterimUsesDirective interim : interimUsesCopy) {
+ UsesDirective d = new UsesDirective(syms.enterClass(currentModule, interim.service));
+ uses.add(d);
+ directives.add(d);
+ }
+ currentModule.uses = uses.toList();
+ ListBuffer<ProvidesDirective> provides = new ListBuffer<>();
+ for (InterimProvidesDirective interim : interimProvidesCopy) {
+ ProvidesDirective d = new ProvidesDirective(syms.enterClass(currentModule, interim.service),
+ syms.enterClass(currentModule, interim.impl));
+ provides.add(d);
+ directives.add(d);
+ }
+ currentModule.provides = provides.toList();
+ currentModule.directives = directives.toList();
+ }
+ }
}