langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
changeset 36526 3b41f1c69604
parent 35810 9ee6e90d679c
child 37001 594b4565d8a4
--- 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();
+        }
+    }
 }