make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java
changeset 50027 69aadf0c1e69
parent 47703 dbfac941197a
child 51799 3fabe59fe4de
--- a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java	Mon May 07 08:56:35 2018 +0200
+++ b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java	Mon May 07 10:37:46 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
 import build.tools.symbolgenerator.CreateSymbols
                                   .ModuleHeaderDescription
                                   .RequiresDescription;
+import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -38,8 +39,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.StringWriter;
 import java.io.Writer;
-import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.FileVisitResult;
 import java.nio.file.FileVisitor;
@@ -49,23 +50,34 @@
 import java.util.stream.Stream;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
+import java.util.TimeZone;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.StandardLocation;
+
+import com.sun.source.util.JavacTask;
 import com.sun.tools.classfile.AccessFlags;
 import com.sun.tools.classfile.Annotation;
 import com.sun.tools.classfile.Annotation.Annotation_element_value;
@@ -115,18 +127,20 @@
 import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
 import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
 import com.sun.tools.classfile.Signature_attribute;
+import com.sun.tools.javac.api.JavacTool;
 import com.sun.tools.javac.jvm.Target;
 import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.Pair;
-import java.io.StringWriter;
 
 /**
  * A tool for processing the .sym.txt files. It allows to:
  *  * convert the .sym.txt into class/sig files for ct.sym
  *  * in cooperation with the adjacent history Probe, construct .sym.txt files for previous platforms
+ *  * enhance existing .sym.txt files with a a new set .sym.txt for the current platform
  *
  * To convert the .sym.txt files to class/sig files from ct.sym, run:
- *     java build.tool.symbolgenerator.CreateSymbols build-ctsym [JOINED_VERSIONS|SEPARATE] <platform-description-file> <target-directory>
+ *     java build.tool.symbolgenerator.CreateSymbols build-ctsym <platform-description-file> <target-directory>
  *
  * The <platform-description-file> is a file of this format:
  *     generate platforms <platform-ids-to-generate separate with ':'>
@@ -166,11 +180,15 @@
  * To generate the .sym.txt files for OpenJDK 7 and 8:
  *     <jdk-7>/bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes
  *     <jdk-8>/bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes
- *     java build.tools.symbolgenerator.CreateSymbols build-description langtools/make/data/symbols $TOPDIR langtools/make/data/symbols/include.list
+ *     java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list
  *                                                    8 OpenJDK8.classes '<none>'
  *                                                    7 OpenJDK7.classes 8
  *
  * Note: the versions are expected to be a single character.
+ *
+ * To enhance existing historical data with data for JDK N, run:
+ *     <jdk-N>/bin/java build.tools.symbolgenerator.CreateSymbols build-description-incremental make/data/symbols/symbols make/data/symbols/include.list
+ *
  */
 public class CreateSymbols {
 
@@ -180,11 +198,11 @@
      */
     @SuppressWarnings("unchecked")
     public void createSymbols(String ctDescriptionFile, String ctSymLocation, CtSymKind ctSymKind) throws IOException {
-        Pair<ClassList, List<ModuleDescription>> data = load(Paths.get(ctDescriptionFile));
-
-        splitHeaders(data.fst);
-
-        for (ModuleDescription md : data.snd) {
+        LoadDescriptions data = load(Paths.get(ctDescriptionFile), null);
+
+        splitHeaders(data.classes);
+
+        for (ModuleDescription md : data.modules.values()) {
             for (ModuleHeaderDescription mhd : md.header) {
                 List<String> versionsList =
                         Collections.singletonList(mhd.versions);
@@ -195,7 +213,7 @@
             }
         }
 
-        for (ClassDescription classDescription : data.fst) {
+        for (ClassDescription classDescription : data.classes) {
             for (ClassHeaderDescription header : classDescription.header) {
                 switch (ctSymKind) {
                     case JOINED_VERSIONS:
@@ -219,7 +237,7 @@
 
     public static String EXTENSION = ".sig";
 
-    Pair<ClassList, List<ModuleDescription>> load(Path ctDescription) throws IOException {
+    LoadDescriptions load(Path ctDescription, String deletePlatform) throws IOException {
         List<PlatformInput> platforms = new ArrayList<>();
         Set<String> generatePlatforms = null;
 
@@ -228,11 +246,14 @@
                 switch (reader.lineKey) {
                     case "generate":
                         String[] platformsAttr = reader.attributes.get("platforms").split(":");
-                        generatePlatforms = new HashSet<>(Arrays.asList(platformsAttr));
+                        generatePlatforms = new HashSet<>(List.of(platformsAttr));
+                        generatePlatforms.remove(deletePlatform);
                         reader.moveNext();
                         break;
                     case "platform":
-                        platforms.add(PlatformInput.load(reader));
+                        PlatformInput platform = PlatformInput.load(reader);
+                        if (!platform.version.equals(deletePlatform))
+                            platforms.add(platform);
                         reader.moveNext();
                         break;
                     default:
@@ -250,7 +271,9 @@
                 addNewVersion(cd.fields, platform.basePlatform, platform.version);
                 addNewVersion(cd.methods, platform.basePlatform, platform.version);
             }
-            //XXX: enhance module versions
+            for (ModuleDescription md : modules.values()) {
+                addNewVersion(md.header, platform.basePlatform, platform.version);
+            }
             for (String input : platform.files) {
                 Path inputFile = ctDescription.getParent().resolve(input);
                 try (LineBasedReader reader = new LineBasedReader(inputFile)) {
@@ -270,13 +293,23 @@
                                 cd.read(reader, platform.basePlatform,
                                         platform.version);
                                 break;
-                            case "module":
+                            case "module": {
                                 ModuleDescription md =
                                         modules.computeIfAbsent(nameAttr,
                                                 n -> new ModuleDescription());
                                 md.read(reader, platform.basePlatform,
                                         platform.version);
                                 break;
+                            }
+                            case "-module": {
+                                ModuleDescription md =
+                                        modules.computeIfAbsent(nameAttr,
+                                                n -> new ModuleDescription());
+                                removeVersion(md.header, h -> true,
+                                              platform.version);
+                                reader.moveNext();
+                                break;
+                            }
                         }
                     }
                 }
@@ -323,7 +356,7 @@
             result.add(desc);
         }
 
-        List<ModuleDescription> moduleList = new ArrayList<>();
+        Map<String, ModuleDescription> moduleList = new HashMap<>();
 
         for (ModuleDescription desc : modules.values()) {
             Iterator<ModuleHeaderDescription> mhdIt = desc.header.iterator();
@@ -340,10 +373,25 @@
                 continue;
             }
 
-            moduleList.add(desc);
+            moduleList.put(desc.name, desc);
         }
 
-        return Pair.of(result, moduleList);
+        return new LoadDescriptions(result, moduleList, platforms);
+    }
+
+    static final class LoadDescriptions {
+        public final ClassList classes;
+        public final Map<String, ModuleDescription> modules;
+        public final List<PlatformInput> versions;
+
+        public LoadDescriptions(ClassList classes,
+                                Map<String, ModuleDescription>  modules,
+                                List<PlatformInput> versions) {
+            this.classes = classes;
+            this.modules = modules;
+            this.versions = versions;
+        }
+
     }
 
     static final class LineBasedReader implements AutoCloseable {
@@ -423,7 +471,7 @@
         public static PlatformInput load(LineBasedReader in) throws IOException {
             return new PlatformInput(in.attributes.get("version"),
                                      in.attributes.get("base"),
-                                     Arrays.asList(in.attributes.get("files").split(":")));
+                                     List.of(in.attributes.get("files").split(":")));
         }
     }
 
@@ -792,7 +840,7 @@
 
     private void addAttributes(MethodDescription desc, List<CPInfo> constantPool, Map<String, Attribute> attributes) {
         addGenericAttributes(desc, constantPool, attributes);
-        if (desc.thrownTypes != null && !desc.thrownTypes.isEmpty()) {
+        if (desc.thrownTypes != null) {
             int[] exceptions = new int[desc.thrownTypes.size()];
             int i = 0;
             for (String exc : desc.thrownTypes) {
@@ -1081,175 +1129,228 @@
         Map<String, ModuleDescription> modules = new HashMap<>();
 
         for (VersionDescription desc : versions) {
-            Map<String, ModuleDescription> currentVersionModules =
-                    new HashMap<>();
+            List<byte[]> classFileData = new ArrayList<>();
+
             try (BufferedReader descIn =
                     Files.newBufferedReader(Paths.get(desc.classes))) {
-                String classFileData;
-
-                while ((classFileData = descIn.readLine()) != null) {
+                String line;
+                while ((line = descIn.readLine()) != null) {
                     ByteArrayOutputStream data = new ByteArrayOutputStream();
-                    for (int i = 0; i < classFileData.length(); i += 2) {
-                        String hex = classFileData.substring(i, i + 2);
-                        data.write(Integer.parseInt(hex, 16));
-                    }
-                    try (InputStream in =
-                            new ByteArrayInputStream(data.toByteArray())) {
-                        inspectModuleInfoClassFile(in,
-                                currentVersionModules, desc.version);
-                    } catch (IOException | ConstantPoolException ex) {
-                        throw new IllegalStateException(ex);
-                    }
-                }
-            }
-
-            ExcludeIncludeList currentEIList = excludesIncludes;
-
-            if (!currentVersionModules.isEmpty()) {
-                Set<String> includes = new HashSet<>();
-
-                for (ModuleDescription md : currentVersionModules.values()) {
-                    md.header.get(0).exports.stream().map(e -> e + '/')
-                                            .forEach(includes::add);
-                }
-
-                currentEIList = new ExcludeIncludeList(includes,
-                                                       Collections.emptySet());
-            }
-
-            ClassList currentVersionClasses = new ClassList();
-            try (BufferedReader descIn =
-                    Files.newBufferedReader(Paths.get(desc.classes))) {
-                String classFileData;
-
-                while ((classFileData = descIn.readLine()) != null) {
-                    ByteArrayOutputStream data = new ByteArrayOutputStream();
-                    for (int i = 0; i < classFileData.length(); i += 2) {
-                        String hex = classFileData.substring(i, i + 2);
+                    for (int i = 0; i < line.length(); i += 2) {
+                        String hex = line.substring(i, i + 2);
                         data.write(Integer.parseInt(hex, 16));
                     }
-                    try (InputStream in =
-                            new ByteArrayInputStream(data.toByteArray())) {
-                        inspectClassFile(in, currentVersionClasses,
-                                         currentEIList, desc.version);
-                    } catch (IOException | ConstantPoolException ex) {
-                        throw new IllegalStateException(ex);
-                    }
+                    classFileData.add(data.toByteArray());
                 }
+            } catch (IOException ex) {
+                throw new IllegalStateException(ex);
             }
 
-            ModuleDescription unsupported =
-                    currentVersionModules.get("jdk.unsupported");
-
-            if (unsupported != null) {
-                for (ClassDescription cd : currentVersionClasses.classes) {
-                    if (unsupported.header
-                                   .get(0)
-                                   .exports
-                                   .contains(cd.packge().replace('.', '/'))) {
-                        ClassHeaderDescription ch = cd.header.get(0);
-                        if (ch.classAnnotations == null) {
-                            ch.classAnnotations = new ArrayList<>();
-                        }
-                        AnnotationDescription ad;
-                        ad = new AnnotationDescription(PROPERITARY_ANNOTATION,
-                                                       Collections.emptyMap());
-                        ch.classAnnotations.add(ad);
-                    }
-                }
+            loadVersionClasses(classes, modules, classFileData, excludesIncludes, desc.version);
+        }
+
+        List<PlatformInput> platforms =
+                versions.stream()
+                        .map(desc -> new PlatformInput(desc.version,
+                                                       desc.primaryBaseline,
+                                                       null))
+                        .collect(Collectors.toList());
+
+        dumpDescriptions(classes, modules, platforms, descDest.resolve("symbols"), args);
+    }
+    //where:
+        private static final String DO_NO_MODIFY =
+            "#\n" +
+            "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" +
+            "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" +
+            "#\n" +
+            "# This code is free software; you can redistribute it and/or modify it\n" +
+            "# under the terms of the GNU General Public License version 2 only, as\n" +
+            "# published by the Free Software Foundation.  Oracle designates this\n" +
+            "# particular file as subject to the \"Classpath\" exception as provided\n" +
+            "# by Oracle in the LICENSE file that accompanied this code.\n" +
+            "#\n" +
+            "# This code is distributed in the hope that it will be useful, but WITHOUT\n" +
+            "# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +
+            "# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n" +
+            "# version 2 for more details (a copy is included in the LICENSE file that\n" +
+            "# accompanied this code).\n" +
+            "#\n" +
+            "# You should have received a copy of the GNU General Public License version\n" +
+            "# 2 along with this work; if not, write to the Free Software Foundation,\n" +
+            "# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n" +
+            "#\n" +
+            "# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n" +
+            "# or visit www.oracle.com if you need additional information or have any\n" +
+            "# questions.\n" +
+            "#\n" +
+            "# ##########################################################\n" +
+            "# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ###\n" +
+            "# ##########################################################\n" +
+            "#\n";
+
+    private void loadVersionClasses(ClassList classes,
+                                    Map<String, ModuleDescription> modules,
+                                    Iterable<byte[]> classData,
+                                    ExcludeIncludeList excludesIncludes,
+                                    String version) {
+        Map<String, ModuleDescription> currentVersionModules =
+                new HashMap<>();
+
+        for (byte[] classFileData : classData) {
+            try (InputStream in = new ByteArrayInputStream(classFileData)) {
+                inspectModuleInfoClassFile(in,
+                                           currentVersionModules, version);
+            } catch (IOException | ConstantPoolException ex) {
+                throw new IllegalStateException(ex);
             }
-
-            Set<String> includedClasses = new HashSet<>();
-            boolean modified;
-
-            do {
-                modified = false;
-
-                for (ClassDescription clazz : currentVersionClasses) {
-                    ClassHeaderDescription header = clazz.header.get(0);
-
-                    if (includeEffectiveAccess(currentVersionClasses, clazz)) {
-                        modified |= include(includedClasses, currentVersionClasses, clazz.name);
+        }
+
+        ExcludeIncludeList currentEIList = excludesIncludes;
+
+        if (!currentVersionModules.isEmpty()) {
+            Set<String> includes = new HashSet<>();
+
+            for (ModuleDescription md : currentVersionModules.values()) {
+                md.header.get(0).exports.stream().map(e -> e + '/')
+                                        .forEach(includes::add);
+            }
+
+            currentEIList = new ExcludeIncludeList(includes,
+                                                   Collections.emptySet());
+        }
+
+        ClassList currentVersionClasses = new ClassList();
+
+        for (byte[] classFileData : classData) {
+            try (InputStream in = new ByteArrayInputStream(classFileData)) {
+                inspectClassFile(in, currentVersionClasses,
+                                 currentEIList, version);
+            } catch (IOException | ConstantPoolException ex) {
+                throw new IllegalStateException(ex);
+            }
+        }
+
+        ModuleDescription unsupported =
+                currentVersionModules.get("jdk.unsupported");
+
+        if (unsupported != null) {
+            for (ClassDescription cd : currentVersionClasses.classes) {
+                if (unsupported.header
+                               .get(0)
+                               .exports
+                               .contains(cd.packge().replace('.', '/'))) {
+                    ClassHeaderDescription ch = cd.header.get(0);
+                    if (ch.classAnnotations == null) {
+                        ch.classAnnotations = new ArrayList<>();
                     }
-
-                    if (includedClasses.contains(clazz.name)) {
-                        modified |= include(includedClasses, currentVersionClasses, header.extendsAttr);
-                        for (String i : header.implementsAttr) {
-                            modified |= include(includedClasses, currentVersionClasses, i);
-                        }
-
-                        modified |= includeOutputType(Collections.singleton(header),
-                                                      h -> "",
-                                                      includedClasses,
-                                                      currentVersionClasses);
-                        modified |= includeOutputType(clazz.fields,
-                                                      f -> f.descriptor,
-                                                      includedClasses,
-                                                      currentVersionClasses);
-                        modified |= includeOutputType(clazz.methods,
-                                                      m -> m.descriptor,
-                                                      includedClasses,
-                                                      currentVersionClasses);
-                    }
-                }
-            } while (modified);
-
-            for (ClassDescription clazz : currentVersionClasses) {
-                if (!includedClasses.contains(clazz.name)) {
-                    continue;
-                }
-
-                ClassHeaderDescription header = clazz.header.get(0);
-
-                if (header.innerClasses != null) {
-                    Iterator<InnerClassInfo> innerClassIt = header.innerClasses.iterator();
-
-                    while(innerClassIt.hasNext()) {
-                        InnerClassInfo ici = innerClassIt.next();
-                        if (!includedClasses.contains(ici.innerClass))
-                            innerClassIt.remove();
-                    }
-                }
-
-                ClassDescription existing = classes.find(clazz.name, true);
-
-                if (existing != null) {
-                    addClassHeader(existing, header, desc.version);
-                    for (MethodDescription currentMethod : clazz.methods) {
-                        addMethod(existing, currentMethod, desc.version);
-                    }
-                    for (FieldDescription currentField : clazz.fields) {
-                        addField(existing, currentField, desc.version);
-                    }
-                } else {
-                    classes.add(clazz);
-                }
-            }
-
-            for (ModuleDescription module : currentVersionModules.values()) {
-                ModuleHeaderDescription header = module.header.get(0);
-
-                if (header.innerClasses != null) {
-                    Iterator<InnerClassInfo> innerClassIt =
-                            header.innerClasses.iterator();
-
-                    while(innerClassIt.hasNext()) {
-                        InnerClassInfo ici = innerClassIt.next();
-                        if (!includedClasses.contains(ici.innerClass))
-                            innerClassIt.remove();
-                    }
-                }
-
-                ModuleDescription existing = modules.get(module.name);
-
-                if (existing != null) {
-                    addModuleHeader(existing, header, desc.version);
-                } else {
-                    modules.put(module.name, module);
+                    AnnotationDescription ad;
+                    ad = new AnnotationDescription(PROPERITARY_ANNOTATION,
+                                                   Collections.emptyMap());
+                    ch.classAnnotations.add(ad);
                 }
             }
         }
 
+        Set<String> includedClasses = new HashSet<>();
+        boolean modified;
+
+        do {
+            modified = false;
+
+            for (ClassDescription clazz : currentVersionClasses) {
+                ClassHeaderDescription header = clazz.header.get(0);
+
+                if (includeEffectiveAccess(currentVersionClasses, clazz)) {
+                    modified |= include(includedClasses, currentVersionClasses, clazz.name);
+                }
+
+                if (includedClasses.contains(clazz.name)) {
+                    modified |= include(includedClasses, currentVersionClasses, header.extendsAttr);
+                    for (String i : header.implementsAttr) {
+                        modified |= include(includedClasses, currentVersionClasses, i);
+                    }
+
+                    modified |= includeOutputType(Collections.singleton(header),
+                                                  h -> "",
+                                                  includedClasses,
+                                                  currentVersionClasses);
+                    modified |= includeOutputType(clazz.fields,
+                                                  f -> f.descriptor,
+                                                  includedClasses,
+                                                  currentVersionClasses);
+                    modified |= includeOutputType(clazz.methods,
+                                                  m -> m.descriptor,
+                                                  includedClasses,
+                                                  currentVersionClasses);
+                }
+            }
+        } while (modified);
+
+        for (ClassDescription clazz : currentVersionClasses) {
+            if (!includedClasses.contains(clazz.name)) {
+                continue;
+            }
+
+            ClassHeaderDescription header = clazz.header.get(0);
+
+            if (header.innerClasses != null) {
+                Iterator<InnerClassInfo> innerClassIt = header.innerClasses.iterator();
+
+                while(innerClassIt.hasNext()) {
+                    InnerClassInfo ici = innerClassIt.next();
+                    if (!includedClasses.contains(ici.innerClass))
+                        innerClassIt.remove();
+                }
+            }
+
+            ClassDescription existing = classes.find(clazz.name, true);
+
+            if (existing != null) {
+                addClassHeader(existing, header, version);
+                for (MethodDescription currentMethod : clazz.methods) {
+                    addMethod(existing, currentMethod, version);
+                }
+                for (FieldDescription currentField : clazz.fields) {
+                    addField(existing, currentField, version);
+                }
+            } else {
+                classes.add(clazz);
+            }
+        }
+
+        for (ModuleDescription module : currentVersionModules.values()) {
+            ModuleHeaderDescription header = module.header.get(0);
+
+            if (header.innerClasses != null) {
+                Iterator<InnerClassInfo> innerClassIt =
+                        header.innerClasses.iterator();
+
+                while(innerClassIt.hasNext()) {
+                    InnerClassInfo ici = innerClassIt.next();
+                    if (!includedClasses.contains(ici.innerClass))
+                        innerClassIt.remove();
+                }
+            }
+
+            ModuleDescription existing = modules.get(module.name);
+
+            if (existing != null) {
+                addModuleHeader(existing, header, version);
+            } else {
+                modules.put(module.name, module);
+            }
+        }
+    }
+    //where:
+        private static final String PROPERITARY_ANNOTATION =
+                "Lsun/Proprietary+Annotation;";
+
+    private void dumpDescriptions(ClassList classes,
+                                  Map<String, ModuleDescription> modules,
+                                  List<PlatformInput> versions,
+                                  Path ctDescriptionFile,
+                                  String[] args) throws IOException {
         classes.sort();
 
         Map<String, String> package2Modules = new HashMap<>();
@@ -1298,46 +1399,52 @@
                .filter(m -> !module2Classes.containsKey(m))
                .forEach(m -> module2Classes.put(m, Collections.emptyList()));
 
-        Path symbolsFile = descDest.resolve("symbols");
-
-        Files.createDirectories(symbolsFile.getParent());
-
-        try (Writer symbolsOut = Files.newBufferedWriter(symbolsFile)) {
-            Map<VersionDescription, List<Path>> outputFiles = new LinkedHashMap<>();
-
-            for (Entry<String, List<ClassDescription>> e : module2Classes.entrySet()) {
-                for (VersionDescription desc : versions) {
-                    StringWriter data = new StringWriter();
-                    ModuleDescription module = modules.get(e.getKey());
-
-                    module.write(data, desc.primaryBaseline, desc.version);
-
-                    for (ClassDescription clazz : e.getValue()) {
-                        clazz.write(data, desc.primaryBaseline, desc.version);
-                    }
-
-                    Path f = descDest.resolve(e.getKey() + "-" + desc.version + ".sym.txt");
-
-                    String dataString = data.toString();
-
-                    if (!dataString.isEmpty()) {
-                        try (Writer out = Files.newBufferedWriter(f)) {
-                            out.append(DO_NO_MODIFY);
-                            out.write(dataString);
+        Files.createDirectories(ctDescriptionFile.getParent());
+
+        int year = Calendar.getInstance(TimeZone.getTimeZone("UTF"), Locale.ROOT)
+                           .get(Calendar.YEAR);
+
+        try (Writer symbolsOut = Files.newBufferedWriter(ctDescriptionFile)) {
+            Map<PlatformInput, List<String>> outputFiles = new LinkedHashMap<>();
+
+            for (PlatformInput desc : versions) {
+                List<String> files = desc.files;
+
+                if (files == null) {
+                    files = new ArrayList<>();
+                    for (Entry<String, List<ClassDescription>> e : module2Classes.entrySet()) {
+                        StringWriter data = new StringWriter();
+                        ModuleDescription module = modules.get(e.getKey());
+
+                        module.write(data, desc.basePlatform, desc.version);
+
+                        for (ClassDescription clazz : e.getValue()) {
+                            clazz.write(data, desc.basePlatform, desc.version);
                         }
 
-                        outputFiles.computeIfAbsent(desc, d -> new ArrayList<>())
-                                   .add(f);
+                        String fileName = e.getKey() + "-" + desc.version + ".sym.txt";
+                        Path f = ctDescriptionFile.getParent().resolve(fileName);
+
+                        String dataString = data.toString();
+
+                        if (!dataString.isEmpty()) {
+                            try (Writer out = Files.newBufferedWriter(f)) {
+                                out.append(DO_NO_MODIFY.replace("{YEAR}", String.valueOf(year)));
+                                out.write(dataString);
+                            }
+                            files.add(f.getFileName().toString());
+                        }
                     }
                 }
+
+                outputFiles.put(desc, files);
             }
-            symbolsOut.append(DO_NO_MODIFY);
+            symbolsOut.append(DO_NO_MODIFY.replace("{YEAR}", "2015, " + year));
             symbolsOut.append("#command used to generate this file:\n");
             symbolsOut.append("#")
                       .append(CreateSymbols.class.getName())
                       .append(" ")
-                      .append(Arrays.asList(args)
-                                    .stream()
+                      .append(Arrays.stream(args)
                                     .collect(Collectors.joining(" ")))
                       .append("\n");
             symbolsOut.append("#\n");
@@ -1347,31 +1454,102 @@
                                       .sorted()
                                       .collect(Collectors.joining(":")))
                       .append("\n");
-            for (Entry<VersionDescription, List<Path>> versionFileEntry : outputFiles.entrySet()) {
+            for (Entry<PlatformInput, List<String>> versionFileEntry : outputFiles.entrySet()) {
                 symbolsOut.append("platform version ")
                           .append(versionFileEntry.getKey().version);
-                if (versionFileEntry.getKey().primaryBaseline != null) {
+                if (versionFileEntry.getKey().basePlatform != null) {
                     symbolsOut.append(" base ")
-                              .append(versionFileEntry.getKey().primaryBaseline);
+                              .append(versionFileEntry.getKey().basePlatform);
                 }
                 symbolsOut.append(" files ")
                           .append(versionFileEntry.getValue()
                                                   .stream()
-                                                  .map(p -> p.getFileName().toString())
+                                                  .map(p -> p)
                                                   .sorted()
                                                   .collect(Collectors.joining(":")))
                           .append("\n");
             }
         }
     }
+
+    public void createIncrementalBaseLine(String ctDescriptionFile,
+                                          String excludeFile,
+                                          String[] args) throws IOException {
+        String specVersion = System.getProperty("java.specification.version");
+        String currentVersion =
+                Integer.toString(Integer.parseInt(specVersion), Character.MAX_RADIX);
+        currentVersion = currentVersion.toUpperCase(Locale.ROOT);
+        Path ctDescriptionPath = Paths.get(ctDescriptionFile).toAbsolutePath();
+        LoadDescriptions data = load(ctDescriptionPath, currentVersion);
+
+        ClassList classes = data.classes;
+        Map<String, ModuleDescription> modules = data.modules;
+        List<PlatformInput> versions = data.versions;
+
+        ExcludeIncludeList excludeList =
+                ExcludeIncludeList.create(excludeFile);
+
+        Iterable<byte[]> classBytes = dumpCurrentClasses();
+        loadVersionClasses(classes, modules, classBytes, excludeList, currentVersion);
+
+        String baseline;
+
+        if (versions.isEmpty()) {
+            baseline = null;
+        } else {
+            baseline = versions.stream()
+                               .sorted((v1, v2) -> v2.version.compareTo(v1.version))
+                               .findFirst()
+                               .get()
+                               .version;
+        }
+
+        versions.add(new PlatformInput(currentVersion, baseline, null));
+        dumpDescriptions(classes, modules, versions, ctDescriptionPath, args);
+    }
+
+    private List<byte[]> dumpCurrentClasses() throws IOException {
+        JavacTool tool = JavacTool.create();
+        Context ctx = new Context();
+        String version = System.getProperty("java.specification.version");
+        JavacTask task = tool.getTask(null, null, null,
+                                      List.of("--release", version),
+                                      null, null, ctx);
+        task.getElements().getTypeElement("java.lang.Object");
+        JavaFileManager fm = ctx.get(JavaFileManager.class);
+
+        List<byte[]> data = new ArrayList<>();
+        for (Location modLoc : LOCATIONS) {
+            for (Set<JavaFileManager.Location> module :
+                    fm.listLocationsForModules(modLoc)) {
+                for (JavaFileManager.Location loc : module) {
+                    Iterable<JavaFileObject> files =
+                            fm.list(loc,
+                                    "",
+                                    EnumSet.of(Kind.CLASS),
+                                    true);
+
+                    for (JavaFileObject jfo : files) {
+                        try (InputStream is = jfo.openInputStream();
+                             InputStream in =
+                                     new BufferedInputStream(is)) {
+                            ByteArrayOutputStream baos =
+                                    new ByteArrayOutputStream();
+
+                            in.transferTo(baos);
+                            data.add(baos.toByteArray());
+                        }
+                    }
+                }
+            }
+        }
+
+        return data;
+    }
     //where:
-        private static final String DO_NO_MODIFY =
-            "# ##########################################################\n" +
-            "# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ###\n" +
-            "# ##########################################################\n" +
-            "#\n";
-        private static final String PROPERITARY_ANNOTATION =
-                "Lsun/Proprietary+Annotation;";
+        private static final List<StandardLocation> LOCATIONS =
+                List.of(StandardLocation.SYSTEM_MODULES,
+                        StandardLocation.UPGRADE_MODULE_PATH);
 
     //<editor-fold defaultstate="collapsed" desc="Class Reading">
     //non-final for tests:
@@ -2006,11 +2184,11 @@
             signature = reader.attributes.get("signature");
             String inClassAnnotations = reader.attributes.get("classAnnotations");
             if (inClassAnnotations != null) {
-                classAnnotations = parseAnnotations(unquote(inClassAnnotations), new int[1]);
+                classAnnotations = parseAnnotations(inClassAnnotations, new int[1]);
             }
             String inRuntimeAnnotations = reader.attributes.get("runtimeAnnotations");
             if (inRuntimeAnnotations != null) {
-                runtimeAnnotations = parseAnnotations(unquote(inRuntimeAnnotations), new int[1]);
+                runtimeAnnotations = parseAnnotations(inRuntimeAnnotations, new int[1]);
             }
         }
 
@@ -2115,6 +2293,7 @@
                         ModuleHeaderDescription mhd =
                                 new ModuleHeaderDescription();
                         mhd.read(reader);
+                        mhd.name = name;
                         mhd.versions = version;
                         header.add(mhd);
                         break;
@@ -2695,7 +2874,11 @@
             name = reader.attributes.get("name");
             descriptor = reader.attributes.get("descriptor");
 
-            thrownTypes = deserializeList(reader.attributes.get("thrownTypes"));
+            String thrownTypesValue = reader.attributes.get("thrownTypes");
+
+            if (thrownTypesValue != null) {
+                thrownTypes = deserializeList(thrownTypesValue);
+            }
 
             String inAnnotationDefaultValue = reader.attributes.get("annotationDefaultValue");
 
@@ -2803,9 +2986,9 @@
             if (inConstantValue != null) {
                 switch (descriptor) {
                     case "Z": constantValue = "true".equals(inConstantValue); break;
-                    case "B": constantValue = Byte.parseByte(inConstantValue); break;
+                    case "B": constantValue = Integer.parseInt(inConstantValue); break;
                     case "C": constantValue = inConstantValue.charAt(0); break;
-                    case "S": constantValue = Short.parseShort(inConstantValue); break;
+                    case "S": constantValue = Integer.parseInt(inConstantValue); break;
                     case "I": constantValue = Integer.parseInt(inConstantValue); break;
                     case "J": constantValue = Long.parseLong(inConstantValue); break;
                     case "F": constantValue = Float.parseFloat(inConstantValue); break;
@@ -3141,7 +3324,7 @@
         serialized = unquote ? unquote(serialized) : serialized;
         if (serialized == null)
             return new ArrayList<>();
-        return new ArrayList<>(Arrays.asList(serialized.split(",")));
+        return new ArrayList<>(List.of(serialized.split(",")));
     }
 
     private static String quote(String value, boolean quoteQuotes) {
@@ -3291,7 +3474,7 @@
         }
 
         switch (args[0]) {
-            case "build-description":
+            case "build-description": {
                 if (args.length < 3) {
                     help();
                     return ;
@@ -3332,6 +3515,16 @@
                                                    descDest,
                                                    args);
                 break;
+            }
+            case "build-description-incremental": {
+                if (args.length != 3) {
+                    help();
+                    return ;
+                }
+
+                new CreateSymbols().createIncrementalBaseLine(args[1], args[2], args);
+                break;
+            }
             case "build-ctsym":
                 if (args.length != 3) {
                     help();