< prev index next >

make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java

Print this page
rev 51104 : imported patch ct.sym-upgrade-code


 103 import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info;
 104 import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
 105 import com.sun.tools.classfile.ConstantPool.CPInfo;
 106 import com.sun.tools.classfile.ConstantPool.InvalidIndex;
 107 import com.sun.tools.classfile.ConstantPoolException;
 108 import com.sun.tools.classfile.ConstantValue_attribute;
 109 import com.sun.tools.classfile.Deprecated_attribute;
 110 import com.sun.tools.classfile.Descriptor;
 111 import com.sun.tools.classfile.Exceptions_attribute;
 112 import com.sun.tools.classfile.Field;
 113 import com.sun.tools.classfile.InnerClasses_attribute;
 114 import com.sun.tools.classfile.InnerClasses_attribute.Info;
 115 import com.sun.tools.classfile.Method;
 116 import com.sun.tools.classfile.ModuleResolution_attribute;
 117 import com.sun.tools.classfile.ModuleTarget_attribute;
 118 import com.sun.tools.classfile.Module_attribute;
 119 import com.sun.tools.classfile.Module_attribute.ExportsEntry;
 120 import com.sun.tools.classfile.Module_attribute.OpensEntry;
 121 import com.sun.tools.classfile.Module_attribute.ProvidesEntry;
 122 import com.sun.tools.classfile.Module_attribute.RequiresEntry;


 123 import com.sun.tools.classfile.RuntimeAnnotations_attribute;
 124 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
 125 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
 126 import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute;
 127 import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
 128 import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
 129 import com.sun.tools.classfile.Signature_attribute;
 130 import com.sun.tools.javac.api.JavacTool;
 131 import com.sun.tools.javac.jvm.Target;
 132 import com.sun.tools.javac.util.Assert;
 133 import com.sun.tools.javac.util.Context;
 134 import com.sun.tools.javac.util.Pair;
 135 
 136 /**
 137  * A tool for processing the .sym.txt files. It allows to:













 138  *  * convert the .sym.txt into class/sig files for ct.sym
 139  *  * in cooperation with the adjacent history Probe, construct .sym.txt files for previous platforms
 140  *  * enhance existing .sym.txt files with a a new set .sym.txt for the current platform
 141  *
 142  * To convert the .sym.txt files to class/sig files from ct.sym, run:
 143  *     java build.tool.symbolgenerator.CreateSymbols build-ctsym <platform-description-file> <target-directory>
 144  *
 145  * The <platform-description-file> is a file of this format:
 146  *     generate platforms <platform-ids-to-generate separate with ':'>
 147  *     platform version <platform-id1> files <.sym.txt files containing history data for given platform, separate with ':'>
 148  *     platform version <platform-id2> base <base-platform-id> files <.sym.txt files containing history data for given platform, separate with ':'>
 149  *
 150  * The content of platform "<base-platform-id>" is also automatically added to the content of
 151  * platform "<platform-id2>", unless explicitly excluded in "<platform-id2>"'s .sym.txt files.
 152  *
 153  * To create the .sym.txt files, first run the history Probe for all the previous platforms:
 154  *     <jdk-N>/bin/java build.tools.symbolgenerator.Probe <classes-for-N>
 155  *
 156  * Where <classes-for-N> is a name of a file into which the classes from the bootclasspath of <jdk-N>
 157  * will be written.


 169  * Several include list files may be specified, separated by File.pathSeparator.
 170  *
 171  * When <diff-against-platformN> is specified, the .sym.txt files for platform N will only contain
 172  * differences between platform N and the specified platform. The first platform (denoted F further)
 173  * that is specified should use literal value "<none>", to have all the APIs of the platform written to
 174  * the .sym.txt files. If there is an existing platform with full .sym.txt files in the repository,
 175  * that platform should be used as the first platform to avoid unnecessary changes to the .sym.txt
 176  * files. The <diff-against-platformN> for platform N should be determined as follows: if N < F, then
 177  * <diff-against-platformN> should be N + 1. If F < N, then <diff-against-platformN> should be N - 1.
 178  * If N is a custom/specialized sub-version of another platform N', then <diff-against-platformN> should be N'.
 179  *
 180  * To generate the .sym.txt files for OpenJDK 7 and 8:
 181  *     <jdk-7>/bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes
 182  *     <jdk-8>/bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes
 183  *     java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list
 184  *                                                    8 OpenJDK8.classes '<none>'
 185  *                                                    7 OpenJDK7.classes 8
 186  *
 187  * Note: the versions are expected to be a single character.
 188  *
 189  * To enhance existing historical data with data for JDK N, run:
 190  *     <jdk-N>/bin/java build.tools.symbolgenerator.CreateSymbols build-description-incremental make/data/symbols/symbols make/data/symbols/include.list
 191  *
 192  */
 193 public class CreateSymbols {
 194 
 195     //<editor-fold defaultstate="collapsed" desc="ct.sym construction">
 196     /**Create sig files for ct.sym reading the classes description from the directory that contains
 197      * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
 198      */
 199     @SuppressWarnings("unchecked")
 200     public void createSymbols(String ctDescriptionFile, String ctSymLocation, CtSymKind ctSymKind) throws IOException {
 201         LoadDescriptions data = load(Paths.get(ctDescriptionFile), null);
 202 
 203         splitHeaders(data.classes);
 204 
 205         for (ModuleDescription md : data.modules.values()) {
 206             for (ModuleHeaderDescription mhd : md.header) {
 207                 List<String> versionsList =
 208                         Collections.singletonList(mhd.versions);
 209                 writeModulesForVersions(ctSymLocation,
 210                                         md,
 211                                         mhd,
 212                                         versionsList);
 213             }
 214         }
 215 
 216         for (ClassDescription classDescription : data.classes) {
 217             for (ClassHeaderDescription header : classDescription.header) {
 218                 switch (ctSymKind) {
 219                     case JOINED_VERSIONS:
 220                         Set<String> jointVersions = new HashSet<>();
 221                         jointVersions.add(header.versions);
 222                         limitJointVersion(jointVersions, classDescription.fields);
 223                         limitJointVersion(jointVersions, classDescription.methods);
 224                         writeClassesForVersions(ctSymLocation, classDescription, header, jointVersions);
 225                         break;
 226                     case SEPARATE:
 227                         Set<String> versions = new HashSet<>();
 228                         for (char v : header.versions.toCharArray()) {
 229                             versions.add("" + v);
 230                         }
 231                         writeClassesForVersions(ctSymLocation, classDescription, header, versions);
 232                         break;
 233                 }
 234             }
 235         }
 236     }
 237 
 238     public static String EXTENSION = ".sig";
 239 
 240     LoadDescriptions load(Path ctDescription, String deletePlatform) throws IOException {
 241         List<PlatformInput> platforms = new ArrayList<>();























 242         Set<String> generatePlatforms = null;
 243 
 244         try (LineBasedReader reader = new LineBasedReader(ctDescription)) {
 245             while (reader.hasNext()) {
 246                 switch (reader.lineKey) {
 247                     case "generate":
 248                         String[] platformsAttr = reader.attributes.get("platforms").split(":");
 249                         generatePlatforms = new HashSet<>(List.of(platformsAttr));
 250                         generatePlatforms.remove(deletePlatform);
 251                         reader.moveNext();
 252                         break;
 253                     case "platform":
 254                         PlatformInput platform = PlatformInput.load(reader);
 255                         if (!platform.version.equals(deletePlatform))
 256                             platforms.add(platform);

 257                         reader.moveNext();
 258                         break;
 259                     default:
 260                         throw new IllegalStateException("Unknown key: " + reader.lineKey);
 261                 }
 262             }
 263         }
 264 
 265         Map<String, ClassDescription> classes = new LinkedHashMap<>();
 266         Map<String, ModuleDescription> modules = new LinkedHashMap<>();
 267 
 268         for (PlatformInput platform: platforms) {
 269             for (ClassDescription cd : classes.values()) {
 270                 addNewVersion(cd.header, platform.basePlatform, platform.version);
 271                 addNewVersion(cd.fields, platform.basePlatform, platform.version);
 272                 addNewVersion(cd.methods, platform.basePlatform, platform.version);
 273             }
 274             for (ModuleDescription md : modules.values()) {
 275                 addNewVersion(md.header, platform.basePlatform, platform.version);
 276             }
 277             for (String input : platform.files) {
 278                 Path inputFile = ctDescription.getParent().resolve(input);
 279                 try (LineBasedReader reader = new LineBasedReader(inputFile)) {
 280                     while (reader.hasNext()) {
 281                         String nameAttr = reader.attributes.get("name");
 282                         switch (reader.lineKey) {
 283                             case "class": case "-class":
 284                                 ClassDescription cd =
 285                                         classes.computeIfAbsent(nameAttr,
 286                                                 n -> new ClassDescription());
 287                                 if ("-class".equals(reader.lineKey)) {
 288                                     removeVersion(cd.header, h -> true,
 289                                                   platform.version);
 290                                     reader.moveNext();
 291                                     continue;
 292                                 }
 293                                 cd.read(reader, platform.basePlatform,
 294                                         platform.version);
 295                                 break;
 296                             case "module": {
 297                                 ModuleDescription md =
 298                                         modules.computeIfAbsent(nameAttr,


 359         Map<String, ModuleDescription> moduleList = new HashMap<>();
 360 
 361         for (ModuleDescription desc : modules.values()) {
 362             Iterator<ModuleHeaderDescription> mhdIt = desc.header.iterator();
 363 
 364             while (mhdIt.hasNext()) {
 365                 ModuleHeaderDescription mhd = mhdIt.next();
 366 
 367                 mhd.versions = reduce(mhd.versions, generatePlatforms);
 368                 if (mhd.versions.isEmpty())
 369                     mhdIt.remove();
 370             }
 371 
 372             if (desc.header.isEmpty()) {
 373                 continue;
 374             }
 375 
 376             moduleList.put(desc.name, desc);
 377         }
 378 
 379         return new LoadDescriptions(result, moduleList, platforms);
 380     }
 381 
 382     static final class LoadDescriptions {
 383         public final ClassList classes;
 384         public final Map<String, ModuleDescription> modules;
 385         public final List<PlatformInput> versions;
 386 
 387         public LoadDescriptions(ClassList classes,
 388                                 Map<String, ModuleDescription>  modules,
 389                                 List<PlatformInput> versions) {
 390             this.classes = classes;
 391             this.modules = modules;
 392             this.versions = versions;
 393         }
 394 
 395     }
 396 
 397     static final class LineBasedReader implements AutoCloseable {
 398         private final BufferedReader input;
 399         public String lineKey;


 445         }
 446 
 447         return reduce(original, otherSet);
 448     }
 449 
 450     private static String reduce(String original, Set<String> generate) {
 451         StringBuilder sb = new StringBuilder();
 452 
 453         for (char v : original.toCharArray()) {
 454             if (generate.contains("" + v)) {
 455                 sb.append(v);
 456             }
 457         }
 458         return sb.toString();
 459     }
 460 
 461     private static class PlatformInput {
 462         public final String version;
 463         public final String basePlatform;
 464         public final List<String> files;
 465         public PlatformInput(String version, String basePlatform, List<String> files) {


 466             this.version = version;
 467             this.basePlatform = basePlatform;
 468             this.files = files;
 469         }
 470 
 471         public static PlatformInput load(LineBasedReader in) throws IOException {
 472             return new PlatformInput(in.attributes.get("version"),

 473                                      in.attributes.get("base"),
 474                                      List.of(in.attributes.get("files").split(":")));
 475         }
 476     }
 477 
 478     static void addNewVersion(Collection<? extends FeatureDescription> features,
 479                        String baselineVersion,
 480                        String version) {
 481         features.stream()
 482                 .filter(f -> f.versions.contains(baselineVersion))
 483                 .forEach(f -> f.versions += version);
 484     }
 485 
 486     static <T extends FeatureDescription> void removeVersion(Collection<T> features,
 487                                                              Predicate<T> shouldRemove,
 488                                                              String version) {
 489         for (T existing : features) {
 490             if (shouldRemove.test(existing) && existing.versions.endsWith(version)) {
 491                 existing.versions = existing.versions.replace(version, "");
 492                 return;


 800                                                    String e) {
 801         return new ExportsEntry(addPackageName(cp, e), 0, new int[0]);
 802     }
 803 
 804     private static OpensEntry createOpensEntry(List<CPInfo> cp, String e) {
 805         return new OpensEntry(addPackageName(cp, e), 0, new int[0]);
 806     }
 807 
 808     private static ProvidesEntry createProvidesEntry(List<CPInfo> cp,
 809             ModuleHeaderDescription.ProvidesDescription p) {
 810         final int idx = addClassName(cp, p.interfaceName);
 811         return new ProvidesEntry(idx, p.implNames
 812                                        .stream()
 813                                        .mapToInt(i -> addClassName(cp, i))
 814                                        .toArray());
 815     }
 816 
 817     private void addAttributes(ClassHeaderDescription header,
 818             List<CPInfo> constantPool, Map<String, Attribute> attributes) {
 819         addGenericAttributes(header, constantPool, attributes);
















 820         addInnerClassesAttribute(header, constantPool, attributes);
 821     }
 822 
 823     private void addInnerClassesAttribute(HeaderDescription header,
 824             List<CPInfo> constantPool, Map<String, Attribute> attributes) {
 825         if (header.innerClasses != null && !header.innerClasses.isEmpty()) {
 826             Info[] innerClasses = new Info[header.innerClasses.size()];
 827             int i = 0;
 828             for (InnerClassInfo info : header.innerClasses) {
 829                 innerClasses[i++] =
 830                         new Info(info.innerClass == null ? 0 : addClass(constantPool, info.innerClass),
 831                                  info.outerClass == null ? 0 : addClass(constantPool, info.outerClass),
 832                                  info.innerClassName == null ? 0 : addString(constantPool, info.innerClassName),
 833                                  new AccessFlags(info.innerClassFlags));
 834             }
 835             int attributeString = addString(constantPool, Attribute.InnerClasses);
 836             attributes.put(Attribute.InnerClasses,
 837                            new InnerClasses_attribute(attributeString, innerClasses));
 838         }
 839     }


1134             try (BufferedReader descIn =
1135                     Files.newBufferedReader(Paths.get(desc.classes))) {
1136                 String line;
1137                 while ((line = descIn.readLine()) != null) {
1138                     ByteArrayOutputStream data = new ByteArrayOutputStream();
1139                     for (int i = 0; i < line.length(); i += 2) {
1140                         String hex = line.substring(i, i + 2);
1141                         data.write(Integer.parseInt(hex, 16));
1142                     }
1143                     classFileData.add(data.toByteArray());
1144                 }
1145             } catch (IOException ex) {
1146                 throw new IllegalStateException(ex);
1147             }
1148 
1149             loadVersionClasses(classes, modules, classFileData, excludesIncludes, desc.version);
1150         }
1151 
1152         List<PlatformInput> platforms =
1153                 versions.stream()
1154                         .map(desc -> new PlatformInput(desc.version,

1155                                                        desc.primaryBaseline,
1156                                                        null))
1157                         .collect(Collectors.toList());
1158 
1159         dumpDescriptions(classes, modules, platforms, descDest.resolve("symbols"), args);
1160     }
1161     //where:
1162         private static final String DO_NO_MODIFY =
1163             "#\n" +
1164             "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" +
1165             "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" +
1166             "#\n" +
1167             "# This code is free software; you can redistribute it and/or modify it\n" +
1168             "# under the terms of the GNU General Public License version 2 only, as\n" +
1169             "# published by the Free Software Foundation.  Oracle designates this\n" +
1170             "# particular file as subject to the \"Classpath\" exception as provided\n" +
1171             "# by Oracle in the LICENSE file that accompanied this code.\n" +
1172             "#\n" +
1173             "# This code is distributed in the hope that it will be useful, but WITHOUT\n" +
1174             "# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +


1277                                                   currentVersionClasses);
1278                     modified |= includeOutputType(clazz.fields,
1279                                                   f -> f.descriptor,
1280                                                   includedClasses,
1281                                                   currentVersionClasses);
1282                     modified |= includeOutputType(clazz.methods,
1283                                                   m -> m.descriptor,
1284                                                   includedClasses,
1285                                                   currentVersionClasses);
1286                 }
1287             }
1288         } while (modified);
1289 
1290         for (ClassDescription clazz : currentVersionClasses) {
1291             if (!includedClasses.contains(clazz.name)) {
1292                 continue;
1293             }
1294 
1295             ClassHeaderDescription header = clazz.header.get(0);
1296 










1297             if (header.innerClasses != null) {
1298                 Iterator<InnerClassInfo> innerClassIt = header.innerClasses.iterator();
1299 
1300                 while(innerClassIt.hasNext()) {
1301                     InnerClassInfo ici = innerClassIt.next();
1302                     if (!includedClasses.contains(ici.innerClass))
1303                         innerClassIt.remove();
1304                 }
1305             }
1306 
1307             ClassDescription existing = classes.find(clazz.name, true);
1308 
1309             if (existing != null) {
1310                 addClassHeader(existing, header, version);
1311                 for (MethodDescription currentMethod : clazz.methods) {
1312                     addMethod(existing, currentMethod, version);
1313                 }
1314                 for (FieldDescription currentField : clazz.fields) {
1315                     addField(existing, currentField, version);
1316                 }


1338             if (existing != null) {
1339                 addModuleHeader(existing, header, version);
1340             } else {
1341                 modules.put(module.name, module);
1342             }
1343         }
1344     }
1345     //where:
1346         private static final String PROPERITARY_ANNOTATION =
1347                 "Lsun/Proprietary+Annotation;";
1348 
1349     private void dumpDescriptions(ClassList classes,
1350                                   Map<String, ModuleDescription> modules,
1351                                   List<PlatformInput> versions,
1352                                   Path ctDescriptionFile,
1353                                   String[] args) throws IOException {
1354         classes.sort();
1355 
1356         Map<String, String> package2Modules = new HashMap<>();
1357 




1358         for (ModuleDescription md : modules.values()) {
1359             md.header
1360               .stream()
1361               .filter(h -> h.versions.contains("9"))
1362               .flatMap(h -> h.exports.stream())
1363               .map(p -> p.replace('/', '.'))
1364               .forEach(p -> package2Modules.put(p, md.name));
1365         }

1366 
1367         package2Modules.put("java.awt.dnd.peer", "java.desktop");
1368         package2Modules.put("java.awt.peer", "java.desktop");
1369         package2Modules.put("jdk", "java.base");
1370 
1371         Map<String, List<ClassDescription>> module2Classes = new HashMap<>();
1372 
1373         for (ClassDescription clazz : classes) {
1374             String pack = clazz.packge();
1375             String module = package2Modules.get(pack);
1376 
1377             if (module == null) {
1378                 module = "java.base";
1379 
1380                 OUTER: while (!pack.isEmpty()) {
1381                     for (Entry<String, String> p2M : package2Modules.entrySet()) {
1382                         if (p2M.getKey().startsWith(pack)) {
1383                             module = p2M.getValue();
1384                             break OUTER;
1385                         }


1463                 }
1464                 symbolsOut.append(" files ")
1465                           .append(versionFileEntry.getValue()
1466                                                   .stream()
1467                                                   .map(p -> p)
1468                                                   .sorted()
1469                                                   .collect(Collectors.joining(":")))
1470                           .append("\n");
1471             }
1472         }
1473     }
1474 
1475     public void createIncrementalBaseLine(String ctDescriptionFile,
1476                                           String excludeFile,
1477                                           String[] args) throws IOException {
1478         String specVersion = System.getProperty("java.specification.version");
1479         String currentVersion =
1480                 Integer.toString(Integer.parseInt(specVersion), Character.MAX_RADIX);
1481         currentVersion = currentVersion.toUpperCase(Locale.ROOT);
1482         Path ctDescriptionPath = Paths.get(ctDescriptionFile).toAbsolutePath();
1483         LoadDescriptions data = load(ctDescriptionPath, currentVersion);
1484 
1485         ClassList classes = data.classes;
1486         Map<String, ModuleDescription> modules = data.modules;
1487         List<PlatformInput> versions = data.versions;
1488 
1489         ExcludeIncludeList excludeList =
1490                 ExcludeIncludeList.create(excludeFile);
1491 
1492         Iterable<byte[]> classBytes = dumpCurrentClasses();
1493         loadVersionClasses(classes, modules, classBytes, excludeList, currentVersion);
1494 
1495         String baseline;
1496 
1497         if (versions.isEmpty()) {
1498             baseline = null;
1499         } else {
1500             baseline = versions.stream()
1501                                .sorted((v1, v2) -> v2.version.compareTo(v1.version))
1502                                .findFirst()
1503                                .get()
1504                                .version;
1505         }
1506 
1507         versions.add(new PlatformInput(currentVersion, baseline, null));
1508         dumpDescriptions(classes, modules, versions, ctDescriptionPath, args);
1509     }
1510 
1511     private List<byte[]> dumpCurrentClasses() throws IOException {
1512         JavacTool tool = JavacTool.create();
1513         Context ctx = new Context();
1514         String version = System.getProperty("java.specification.version");
1515         JavacTask task = tool.getTask(null, null, null,
1516                                       List.of("--release", version),
1517                                       null, null, ctx);
1518         task.getElements().getTypeElement("java.lang.Object");
1519         JavaFileManager fm = ctx.get(JavaFileManager.class);
1520 
1521         List<byte[]> data = new ArrayList<>();
1522         for (Location modLoc : LOCATIONS) {
1523             for (Set<JavaFileManager.Location> module :
1524                     fm.listLocationsForModules(modLoc)) {
1525                 for (JavaFileManager.Location loc : module) {
1526                     Iterable<JavaFileObject> files =
1527                             fm.list(loc,


1865                 ModuleTarget_attribute mod = (ModuleTarget_attribute) attr;
1866                 if (mod.target_platform_index != 0) {
1867                     header.moduleTarget =
1868                             cf.constant_pool
1869                               .getUTF8Value(mod.target_platform_index);
1870                 }
1871                 break;
1872             }
1873             case Attribute.ModuleResolution: {
1874                 assert feature instanceof ModuleHeaderDescription;
1875                 ModuleHeaderDescription header =
1876                         (ModuleHeaderDescription) feature;
1877                 ModuleResolution_attribute mod =
1878                         (ModuleResolution_attribute) attr;
1879                 header.moduleResolution = mod.resolution_flags;
1880                 break;
1881             }
1882             case Attribute.ModulePackages:
1883             case Attribute.ModuleHashes:
1884                 break;
















1885             default:
1886                 throw new IllegalStateException("Unhandled attribute: " +
1887                                                 attrName);
1888         }
1889 
1890         return true;
1891     }
1892 
1893     private static String getClassName(ClassFile cf, int idx) {
1894         try {
1895             return cf.constant_pool.getClassInfo(idx).getName();
1896         } catch (InvalidIndex ex) {
1897             throw new IllegalStateException(ex);
1898         } catch (ConstantPool.UnexpectedEntry ex) {
1899             throw new IllegalStateException(ex);
1900         } catch (ConstantPoolException ex) {
1901             throw new IllegalStateException(ex);
1902         }
1903     }
1904 


2645                 }
2646             }
2647         }
2648 
2649         public String packge() {
2650             String pack;
2651             int lastSlash = name.lastIndexOf('/');
2652             if (lastSlash != (-1)) {
2653                 pack = name.substring(0, lastSlash).replace('/', '.');
2654             } else {
2655                 pack = "";
2656             }
2657 
2658             return pack;
2659         }
2660     }
2661 
2662     static class ClassHeaderDescription extends HeaderDescription {
2663         String extendsAttr;
2664         List<String> implementsAttr;


2665 
2666         @Override
2667         public int hashCode() {
2668             int hash = super.hashCode();
2669             hash = 17 * hash + Objects.hashCode(this.extendsAttr);
2670             hash = 17 * hash + Objects.hashCode(this.implementsAttr);


2671             return hash;
2672         }
2673 
2674         @Override
2675         public boolean equals(Object obj) {
2676             if (obj == null) {
2677                 return false;
2678             }
2679             if (!super.equals(obj)) {
2680                 return false;
2681             }
2682             final ClassHeaderDescription other = (ClassHeaderDescription) obj;
2683             if (!Objects.equals(this.extendsAttr, other.extendsAttr)) {
2684                 return false;
2685             }
2686             if (!Objects.equals(this.implementsAttr, other.implementsAttr)) {
2687                 return false;
2688             }






2689             return true;
2690         }
2691 
2692         @Override
2693         public void write(Appendable output, String baselineVersion, String version) throws IOException {
2694             if (!versions.contains(version) ||
2695                 (baselineVersion != null && versions.contains(baselineVersion) && versions.contains(version)))
2696                 return ;
2697             output.append("header");
2698             if (extendsAttr != null)
2699                 output.append(" extends " + extendsAttr);
2700             if (implementsAttr != null && !implementsAttr.isEmpty())
2701                 output.append(" implements " + serializeList(implementsAttr));




2702             writeAttributes(output);
2703             output.append("\n");
2704             writeInnerClasses(output, baselineVersion, version);
2705         }
2706 
2707         @Override
2708         public boolean read(LineBasedReader reader) throws IOException {
2709             if (!"header".equals(reader.lineKey))
2710                 return false;
2711 
2712             extendsAttr = reader.attributes.get("extends");
2713             String elementsList = reader.attributes.get("implements");
2714             implementsAttr = deserializeList(elementsList);
2715 




2716             readAttributes(reader);
2717             reader.moveNext();
2718             readInnerClasses(reader);
2719 
2720             return true;
2721         }
2722 
2723     }
2724 
2725     static abstract class HeaderDescription extends FeatureDescription {
2726         List<InnerClassInfo> innerClasses;
2727 
2728         @Override
2729         public int hashCode() {
2730             int hash = super.hashCode();
2731             hash = 19 * hash + Objects.hashCode(this.innerClasses);
2732             return hash;
2733         }
2734 
2735         @Override


3509 
3510                 ExcludeIncludeList excludeList =
3511                         ExcludeIncludeList.create(args[2]);
3512 
3513                 new CreateSymbols().createBaseLine(versions,
3514                                                    excludeList,
3515                                                    descDest,
3516                                                    args);
3517                 break;
3518             }
3519             case "build-description-incremental": {
3520                 if (args.length != 3) {
3521                     help();
3522                     return ;
3523                 }
3524 
3525                 new CreateSymbols().createIncrementalBaseLine(args[1], args[2], args);
3526                 break;
3527             }
3528             case "build-ctsym":
3529                 if (args.length != 3) {
3530                     help();
3531                     return ;
3532                 }
3533 
3534                 new CreateSymbols().createSymbols(args[1],
3535                                                   args[2],

3536                                                   CtSymKind.JOINED_VERSIONS);
3537                 break;
3538         }
3539     }
3540 
3541 }


 103 import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info;
 104 import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
 105 import com.sun.tools.classfile.ConstantPool.CPInfo;
 106 import com.sun.tools.classfile.ConstantPool.InvalidIndex;
 107 import com.sun.tools.classfile.ConstantPoolException;
 108 import com.sun.tools.classfile.ConstantValue_attribute;
 109 import com.sun.tools.classfile.Deprecated_attribute;
 110 import com.sun.tools.classfile.Descriptor;
 111 import com.sun.tools.classfile.Exceptions_attribute;
 112 import com.sun.tools.classfile.Field;
 113 import com.sun.tools.classfile.InnerClasses_attribute;
 114 import com.sun.tools.classfile.InnerClasses_attribute.Info;
 115 import com.sun.tools.classfile.Method;
 116 import com.sun.tools.classfile.ModuleResolution_attribute;
 117 import com.sun.tools.classfile.ModuleTarget_attribute;
 118 import com.sun.tools.classfile.Module_attribute;
 119 import com.sun.tools.classfile.Module_attribute.ExportsEntry;
 120 import com.sun.tools.classfile.Module_attribute.OpensEntry;
 121 import com.sun.tools.classfile.Module_attribute.ProvidesEntry;
 122 import com.sun.tools.classfile.Module_attribute.RequiresEntry;
 123 import com.sun.tools.classfile.NestHost_attribute;
 124 import com.sun.tools.classfile.NestMembers_attribute;
 125 import com.sun.tools.classfile.RuntimeAnnotations_attribute;
 126 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
 127 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
 128 import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute;
 129 import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
 130 import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
 131 import com.sun.tools.classfile.Signature_attribute;
 132 import com.sun.tools.javac.api.JavacTool;
 133 import com.sun.tools.javac.jvm.Target;
 134 import com.sun.tools.javac.util.Assert;
 135 import com.sun.tools.javac.util.Context;
 136 import com.sun.tools.javac.util.Pair;
 137 
 138 /**
 139  * A tool for processing the .sym.txt files.
 140  *
 141  * To add historical data for JDK N, N >= 11, do the following:
 142  *  * cd <open-jdk-checkout>/make/data/symbols
 143  *  * <jdk-N>/bin/java --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
 144  *                     --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
 145  *                     --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \
 146  *                     --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
 147  *                     --add-modules jdk.jdeps \
 148  *                     ../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \
 149  *                     build-description-incremental symbols include.list
 150  *  * sanity-check the new and updates files in make/data/symbols and commit them
 151  *
 152  * The tools allows to:
 153  *  * convert the .sym.txt into class/sig files for ct.sym
 154  *  * in cooperation with the adjacent history Probe, construct .sym.txt files for previous platforms
 155  *  * enhance existing .sym.txt files with a a new set .sym.txt for the current platform
 156  *
 157  * To convert the .sym.txt files to class/sig files from ct.sym, run:
 158  *     java build.tool.symbolgenerator.CreateSymbols build-ctsym <platform-description-file> <target-directory>
 159  *
 160  * The <platform-description-file> is a file of this format:
 161  *     generate platforms <platform-ids-to-generate separate with ':'>
 162  *     platform version <platform-id1> files <.sym.txt files containing history data for given platform, separate with ':'>
 163  *     platform version <platform-id2> base <base-platform-id> files <.sym.txt files containing history data for given platform, separate with ':'>
 164  *
 165  * The content of platform "<base-platform-id>" is also automatically added to the content of
 166  * platform "<platform-id2>", unless explicitly excluded in "<platform-id2>"'s .sym.txt files.
 167  *
 168  * To create the .sym.txt files, first run the history Probe for all the previous platforms:
 169  *     <jdk-N>/bin/java build.tools.symbolgenerator.Probe <classes-for-N>
 170  *
 171  * Where <classes-for-N> is a name of a file into which the classes from the bootclasspath of <jdk-N>
 172  * will be written.


 184  * Several include list files may be specified, separated by File.pathSeparator.
 185  *
 186  * When <diff-against-platformN> is specified, the .sym.txt files for platform N will only contain
 187  * differences between platform N and the specified platform. The first platform (denoted F further)
 188  * that is specified should use literal value "<none>", to have all the APIs of the platform written to
 189  * the .sym.txt files. If there is an existing platform with full .sym.txt files in the repository,
 190  * that platform should be used as the first platform to avoid unnecessary changes to the .sym.txt
 191  * files. The <diff-against-platformN> for platform N should be determined as follows: if N < F, then
 192  * <diff-against-platformN> should be N + 1. If F < N, then <diff-against-platformN> should be N - 1.
 193  * If N is a custom/specialized sub-version of another platform N', then <diff-against-platformN> should be N'.
 194  *
 195  * To generate the .sym.txt files for OpenJDK 7 and 8:
 196  *     <jdk-7>/bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes
 197  *     <jdk-8>/bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes
 198  *     java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list
 199  *                                                    8 OpenJDK8.classes '<none>'
 200  *                                                    7 OpenJDK7.classes 8
 201  *
 202  * Note: the versions are expected to be a single character.
 203  *



 204  */
 205 public class CreateSymbols {
 206 
 207     //<editor-fold defaultstate="collapsed" desc="ct.sym construction">
 208     /**Create sig files for ct.sym reading the classes description from the directory that contains
 209      * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
 210      */
 211     @SuppressWarnings("unchecked")
 212     public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFile, String ctSymLocation, CtSymKind ctSymKind) throws IOException {
 213         LoadDescriptions data = load(Paths.get(ctDescriptionFileExtra), Paths.get(ctDescriptionFile), null);
 214 
 215         splitHeaders(data.classes);
 216 
 217         for (ModuleDescription md : data.modules.values()) {
 218             for (ModuleHeaderDescription mhd : md.header) {
 219                 List<String> versionsList =
 220                         Collections.singletonList(mhd.versions);
 221                 writeModulesForVersions(ctSymLocation,
 222                                         md,
 223                                         mhd,
 224                                         versionsList);
 225             }
 226         }
 227 
 228         for (ClassDescription classDescription : data.classes) {
 229             for (ClassHeaderDescription header : classDescription.header) {
 230                 switch (ctSymKind) {
 231                     case JOINED_VERSIONS:
 232                         Set<String> jointVersions = new HashSet<>();
 233                         jointVersions.add(header.versions);
 234                         limitJointVersion(jointVersions, classDescription.fields);
 235                         limitJointVersion(jointVersions, classDescription.methods);
 236                         writeClassesForVersions(ctSymLocation, classDescription, header, jointVersions);
 237                         break;
 238                     case SEPARATE:
 239                         Set<String> versions = new HashSet<>();
 240                         for (char v : header.versions.toCharArray()) {
 241                             versions.add("" + v);
 242                         }
 243                         writeClassesForVersions(ctSymLocation, classDescription, header, versions);
 244                         break;
 245                 }
 246             }
 247         }
 248     }
 249 
 250     public static String EXTENSION = ".sig";
 251 
 252     LoadDescriptions load(Path ctDescriptionWithExtraContent, Path ctDescriptionOpen, String deletePlatform) throws IOException {
 253         Map<String, PlatformInput> platforms = new LinkedHashMap<>();
 254 
 255         if (ctDescriptionWithExtraContent != null && Files.isRegularFile(ctDescriptionWithExtraContent)) {
 256             try (LineBasedReader reader = new LineBasedReader(ctDescriptionWithExtraContent)) {
 257                 while (reader.hasNext()) {
 258                     switch (reader.lineKey) {
 259                         case "generate":
 260                             //ignore
 261                             reader.moveNext();
 262                             break;
 263                         case "platform":
 264                             PlatformInput platform = PlatformInput.load(ctDescriptionWithExtraContent,
 265                                                                         reader);
 266                             if (!platform.version.equals(deletePlatform))
 267                                 platforms.put(platform.version, platform);
 268                             reader.moveNext();
 269                             break;
 270                         default:
 271                             throw new IllegalStateException("Unknown key: " + reader.lineKey);
 272                     }
 273                 }
 274             }
 275         }
 276 
 277         Set<String> generatePlatforms = null;
 278 
 279         try (LineBasedReader reader = new LineBasedReader(ctDescriptionOpen)) {
 280             while (reader.hasNext()) {
 281                 switch (reader.lineKey) {
 282                     case "generate":
 283                         String[] platformsAttr = reader.attributes.get("platforms").split(":");
 284                         generatePlatforms = new HashSet<>(List.of(platformsAttr));
 285                         generatePlatforms.remove(deletePlatform);
 286                         reader.moveNext();
 287                         break;
 288                     case "platform":
 289                         PlatformInput platform = PlatformInput.load(ctDescriptionOpen, reader);
 290                         if (!platform.version.equals(deletePlatform) &&
 291                             !platforms.containsKey(platform.version))
 292                             platforms.put(platform.version, platform);
 293                         reader.moveNext();
 294                         break;
 295                     default:
 296                         throw new IllegalStateException("Unknown key: " + reader.lineKey);
 297                 }
 298             }
 299         }
 300 
 301         Map<String, ClassDescription> classes = new LinkedHashMap<>();
 302         Map<String, ModuleDescription> modules = new LinkedHashMap<>();
 303 
 304         for (PlatformInput platform : platforms.values()) {
 305             for (ClassDescription cd : classes.values()) {
 306                 addNewVersion(cd.header, platform.basePlatform, platform.version);
 307                 addNewVersion(cd.fields, platform.basePlatform, platform.version);
 308                 addNewVersion(cd.methods, platform.basePlatform, platform.version);
 309             }
 310             for (ModuleDescription md : modules.values()) {
 311                 addNewVersion(md.header, platform.basePlatform, platform.version);
 312             }
 313             for (String input : platform.files) {
 314                 Path inputFile = platform.ctDescription.getParent().resolve(input);
 315                 try (LineBasedReader reader = new LineBasedReader(inputFile)) {
 316                     while (reader.hasNext()) {
 317                         String nameAttr = reader.attributes.get("name");
 318                         switch (reader.lineKey) {
 319                             case "class": case "-class":
 320                                 ClassDescription cd =
 321                                         classes.computeIfAbsent(nameAttr,
 322                                                 n -> new ClassDescription());
 323                                 if ("-class".equals(reader.lineKey)) {
 324                                     removeVersion(cd.header, h -> true,
 325                                                   platform.version);
 326                                     reader.moveNext();
 327                                     continue;
 328                                 }
 329                                 cd.read(reader, platform.basePlatform,
 330                                         platform.version);
 331                                 break;
 332                             case "module": {
 333                                 ModuleDescription md =
 334                                         modules.computeIfAbsent(nameAttr,


 395         Map<String, ModuleDescription> moduleList = new HashMap<>();
 396 
 397         for (ModuleDescription desc : modules.values()) {
 398             Iterator<ModuleHeaderDescription> mhdIt = desc.header.iterator();
 399 
 400             while (mhdIt.hasNext()) {
 401                 ModuleHeaderDescription mhd = mhdIt.next();
 402 
 403                 mhd.versions = reduce(mhd.versions, generatePlatforms);
 404                 if (mhd.versions.isEmpty())
 405                     mhdIt.remove();
 406             }
 407 
 408             if (desc.header.isEmpty()) {
 409                 continue;
 410             }
 411 
 412             moduleList.put(desc.name, desc);
 413         }
 414 
 415         return new LoadDescriptions(result, moduleList, new ArrayList<>(platforms.values()));
 416     }
 417 
 418     static final class LoadDescriptions {
 419         public final ClassList classes;
 420         public final Map<String, ModuleDescription> modules;
 421         public final List<PlatformInput> versions;
 422 
 423         public LoadDescriptions(ClassList classes,
 424                                 Map<String, ModuleDescription>  modules,
 425                                 List<PlatformInput> versions) {
 426             this.classes = classes;
 427             this.modules = modules;
 428             this.versions = versions;
 429         }
 430 
 431     }
 432 
 433     static final class LineBasedReader implements AutoCloseable {
 434         private final BufferedReader input;
 435         public String lineKey;


 481         }
 482 
 483         return reduce(original, otherSet);
 484     }
 485 
 486     private static String reduce(String original, Set<String> generate) {
 487         StringBuilder sb = new StringBuilder();
 488 
 489         for (char v : original.toCharArray()) {
 490             if (generate.contains("" + v)) {
 491                 sb.append(v);
 492             }
 493         }
 494         return sb.toString();
 495     }
 496 
 497     private static class PlatformInput {
 498         public final String version;
 499         public final String basePlatform;
 500         public final List<String> files;
 501         public final Path ctDescription;
 502         public PlatformInput(Path ctDescription, String version, String basePlatform, List<String> files) {
 503             this.ctDescription = ctDescription;
 504             this.version = version;
 505             this.basePlatform = basePlatform;
 506             this.files = files;
 507         }
 508 
 509         public static PlatformInput load(Path ctDescription, LineBasedReader in) throws IOException {
 510             return new PlatformInput(ctDescription,
 511                                      in.attributes.get("version"),
 512                                      in.attributes.get("base"),
 513                                      List.of(in.attributes.get("files").split(":")));
 514         }
 515     }
 516 
 517     static void addNewVersion(Collection<? extends FeatureDescription> features,
 518                        String baselineVersion,
 519                        String version) {
 520         features.stream()
 521                 .filter(f -> f.versions.contains(baselineVersion))
 522                 .forEach(f -> f.versions += version);
 523     }
 524 
 525     static <T extends FeatureDescription> void removeVersion(Collection<T> features,
 526                                                              Predicate<T> shouldRemove,
 527                                                              String version) {
 528         for (T existing : features) {
 529             if (shouldRemove.test(existing) && existing.versions.endsWith(version)) {
 530                 existing.versions = existing.versions.replace(version, "");
 531                 return;


 839                                                    String e) {
 840         return new ExportsEntry(addPackageName(cp, e), 0, new int[0]);
 841     }
 842 
 843     private static OpensEntry createOpensEntry(List<CPInfo> cp, String e) {
 844         return new OpensEntry(addPackageName(cp, e), 0, new int[0]);
 845     }
 846 
 847     private static ProvidesEntry createProvidesEntry(List<CPInfo> cp,
 848             ModuleHeaderDescription.ProvidesDescription p) {
 849         final int idx = addClassName(cp, p.interfaceName);
 850         return new ProvidesEntry(idx, p.implNames
 851                                        .stream()
 852                                        .mapToInt(i -> addClassName(cp, i))
 853                                        .toArray());
 854     }
 855 
 856     private void addAttributes(ClassHeaderDescription header,
 857             List<CPInfo> constantPool, Map<String, Attribute> attributes) {
 858         addGenericAttributes(header, constantPool, attributes);
 859         if (header.nestHost != null) {
 860             int attributeString = addString(constantPool, Attribute.NestHost);
 861             int nestHost = addClass(constantPool, header.nestHost);
 862             attributes.put(Attribute.NestHost,
 863                            new NestHost_attribute(attributeString, nestHost));
 864         }
 865         if (header.nestMembers != null && !header.nestMembers.isEmpty()) {
 866             int attributeString = addString(constantPool, Attribute.NestMembers);
 867             int[] nestMembers = new int[header.nestMembers.size()];
 868             int i = 0;
 869             for (String intf : header.nestMembers) {
 870                 nestMembers[i++] = addClass(constantPool, intf);
 871             }
 872             attributes.put(Attribute.NestMembers,
 873                            new NestMembers_attribute(attributeString, nestMembers));
 874         }
 875         addInnerClassesAttribute(header, constantPool, attributes);
 876     }
 877 
 878     private void addInnerClassesAttribute(HeaderDescription header,
 879             List<CPInfo> constantPool, Map<String, Attribute> attributes) {
 880         if (header.innerClasses != null && !header.innerClasses.isEmpty()) {
 881             Info[] innerClasses = new Info[header.innerClasses.size()];
 882             int i = 0;
 883             for (InnerClassInfo info : header.innerClasses) {
 884                 innerClasses[i++] =
 885                         new Info(info.innerClass == null ? 0 : addClass(constantPool, info.innerClass),
 886                                  info.outerClass == null ? 0 : addClass(constantPool, info.outerClass),
 887                                  info.innerClassName == null ? 0 : addString(constantPool, info.innerClassName),
 888                                  new AccessFlags(info.innerClassFlags));
 889             }
 890             int attributeString = addString(constantPool, Attribute.InnerClasses);
 891             attributes.put(Attribute.InnerClasses,
 892                            new InnerClasses_attribute(attributeString, innerClasses));
 893         }
 894     }


1189             try (BufferedReader descIn =
1190                     Files.newBufferedReader(Paths.get(desc.classes))) {
1191                 String line;
1192                 while ((line = descIn.readLine()) != null) {
1193                     ByteArrayOutputStream data = new ByteArrayOutputStream();
1194                     for (int i = 0; i < line.length(); i += 2) {
1195                         String hex = line.substring(i, i + 2);
1196                         data.write(Integer.parseInt(hex, 16));
1197                     }
1198                     classFileData.add(data.toByteArray());
1199                 }
1200             } catch (IOException ex) {
1201                 throw new IllegalStateException(ex);
1202             }
1203 
1204             loadVersionClasses(classes, modules, classFileData, excludesIncludes, desc.version);
1205         }
1206 
1207         List<PlatformInput> platforms =
1208                 versions.stream()
1209                         .map(desc -> new PlatformInput(null,
1210                                                        desc.version,
1211                                                        desc.primaryBaseline,
1212                                                        null))
1213                         .collect(Collectors.toList());
1214 
1215         dumpDescriptions(classes, modules, platforms, descDest.resolve("symbols"), args);
1216     }
1217     //where:
1218         private static final String DO_NO_MODIFY =
1219             "#\n" +
1220             "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" +
1221             "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" +
1222             "#\n" +
1223             "# This code is free software; you can redistribute it and/or modify it\n" +
1224             "# under the terms of the GNU General Public License version 2 only, as\n" +
1225             "# published by the Free Software Foundation.  Oracle designates this\n" +
1226             "# particular file as subject to the \"Classpath\" exception as provided\n" +
1227             "# by Oracle in the LICENSE file that accompanied this code.\n" +
1228             "#\n" +
1229             "# This code is distributed in the hope that it will be useful, but WITHOUT\n" +
1230             "# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +


1333                                                   currentVersionClasses);
1334                     modified |= includeOutputType(clazz.fields,
1335                                                   f -> f.descriptor,
1336                                                   includedClasses,
1337                                                   currentVersionClasses);
1338                     modified |= includeOutputType(clazz.methods,
1339                                                   m -> m.descriptor,
1340                                                   includedClasses,
1341                                                   currentVersionClasses);
1342                 }
1343             }
1344         } while (modified);
1345 
1346         for (ClassDescription clazz : currentVersionClasses) {
1347             if (!includedClasses.contains(clazz.name)) {
1348                 continue;
1349             }
1350 
1351             ClassHeaderDescription header = clazz.header.get(0);
1352 
1353             if (header.nestMembers != null) {
1354                 Iterator<String> nestMemberIt = header.nestMembers.iterator();
1355 
1356                 while(nestMemberIt.hasNext()) {
1357                     String member = nestMemberIt.next();
1358                     if (!includedClasses.contains(member))
1359                         nestMemberIt.remove();
1360                 }
1361             }
1362 
1363             if (header.innerClasses != null) {
1364                 Iterator<InnerClassInfo> innerClassIt = header.innerClasses.iterator();
1365 
1366                 while(innerClassIt.hasNext()) {
1367                     InnerClassInfo ici = innerClassIt.next();
1368                     if (!includedClasses.contains(ici.innerClass))
1369                         innerClassIt.remove();
1370                 }
1371             }
1372 
1373             ClassDescription existing = classes.find(clazz.name, true);
1374 
1375             if (existing != null) {
1376                 addClassHeader(existing, header, version);
1377                 for (MethodDescription currentMethod : clazz.methods) {
1378                     addMethod(existing, currentMethod, version);
1379                 }
1380                 for (FieldDescription currentField : clazz.fields) {
1381                     addField(existing, currentField, version);
1382                 }


1404             if (existing != null) {
1405                 addModuleHeader(existing, header, version);
1406             } else {
1407                 modules.put(module.name, module);
1408             }
1409         }
1410     }
1411     //where:
1412         private static final String PROPERITARY_ANNOTATION =
1413                 "Lsun/Proprietary+Annotation;";
1414 
1415     private void dumpDescriptions(ClassList classes,
1416                                   Map<String, ModuleDescription> modules,
1417                                   List<PlatformInput> versions,
1418                                   Path ctDescriptionFile,
1419                                   String[] args) throws IOException {
1420         classes.sort();
1421 
1422         Map<String, String> package2Modules = new HashMap<>();
1423 
1424         versions.stream()
1425                 .filter(v -> "9".compareTo(v.version) <= 0)
1426                 .sorted((v1, v2) -> v1.version.compareTo(v2.version))
1427                 .forEach(v -> {
1428             for (ModuleDescription md : modules.values()) {
1429                 md.header
1430                   .stream()
1431                   .filter(h -> h.versions.contains(v.version))
1432                   .flatMap(h -> h.exports.stream())
1433                   .map(p -> p.replace('/', '.'))
1434                   .forEach(p -> package2Modules.putIfAbsent(p, md.name));
1435             }
1436         });
1437 
1438         package2Modules.put("java.awt.dnd.peer", "java.desktop");
1439         package2Modules.put("java.awt.peer", "java.desktop");
1440         package2Modules.put("jdk", "java.base");
1441 
1442         Map<String, List<ClassDescription>> module2Classes = new HashMap<>();
1443 
1444         for (ClassDescription clazz : classes) {
1445             String pack = clazz.packge();
1446             String module = package2Modules.get(pack);
1447 
1448             if (module == null) {
1449                 module = "java.base";
1450 
1451                 OUTER: while (!pack.isEmpty()) {
1452                     for (Entry<String, String> p2M : package2Modules.entrySet()) {
1453                         if (p2M.getKey().startsWith(pack)) {
1454                             module = p2M.getValue();
1455                             break OUTER;
1456                         }


1534                 }
1535                 symbolsOut.append(" files ")
1536                           .append(versionFileEntry.getValue()
1537                                                   .stream()
1538                                                   .map(p -> p)
1539                                                   .sorted()
1540                                                   .collect(Collectors.joining(":")))
1541                           .append("\n");
1542             }
1543         }
1544     }
1545 
1546     public void createIncrementalBaseLine(String ctDescriptionFile,
1547                                           String excludeFile,
1548                                           String[] args) throws IOException {
1549         String specVersion = System.getProperty("java.specification.version");
1550         String currentVersion =
1551                 Integer.toString(Integer.parseInt(specVersion), Character.MAX_RADIX);
1552         currentVersion = currentVersion.toUpperCase(Locale.ROOT);
1553         Path ctDescriptionPath = Paths.get(ctDescriptionFile).toAbsolutePath();
1554         LoadDescriptions data = load(null, ctDescriptionPath, currentVersion);
1555 
1556         ClassList classes = data.classes;
1557         Map<String, ModuleDescription> modules = data.modules;
1558         List<PlatformInput> versions = data.versions;
1559 
1560         ExcludeIncludeList excludeList =
1561                 ExcludeIncludeList.create(excludeFile);
1562 
1563         Iterable<byte[]> classBytes = dumpCurrentClasses();
1564         loadVersionClasses(classes, modules, classBytes, excludeList, currentVersion);
1565 
1566         String baseline;
1567 
1568         if (versions.isEmpty()) {
1569             baseline = null;
1570         } else {
1571             baseline = versions.stream()
1572                                .sorted((v1, v2) -> v2.version.compareTo(v1.version))
1573                                .findFirst()
1574                                .get()
1575                                .version;
1576         }
1577 
1578         versions.add(new PlatformInput(null, currentVersion, baseline, null));
1579         dumpDescriptions(classes, modules, versions, ctDescriptionPath, args);
1580     }
1581 
1582     private List<byte[]> dumpCurrentClasses() throws IOException {
1583         JavacTool tool = JavacTool.create();
1584         Context ctx = new Context();
1585         String version = System.getProperty("java.specification.version");
1586         JavacTask task = tool.getTask(null, null, null,
1587                                       List.of("--release", version),
1588                                       null, null, ctx);
1589         task.getElements().getTypeElement("java.lang.Object");
1590         JavaFileManager fm = ctx.get(JavaFileManager.class);
1591 
1592         List<byte[]> data = new ArrayList<>();
1593         for (Location modLoc : LOCATIONS) {
1594             for (Set<JavaFileManager.Location> module :
1595                     fm.listLocationsForModules(modLoc)) {
1596                 for (JavaFileManager.Location loc : module) {
1597                     Iterable<JavaFileObject> files =
1598                             fm.list(loc,


1936                 ModuleTarget_attribute mod = (ModuleTarget_attribute) attr;
1937                 if (mod.target_platform_index != 0) {
1938                     header.moduleTarget =
1939                             cf.constant_pool
1940                               .getUTF8Value(mod.target_platform_index);
1941                 }
1942                 break;
1943             }
1944             case Attribute.ModuleResolution: {
1945                 assert feature instanceof ModuleHeaderDescription;
1946                 ModuleHeaderDescription header =
1947                         (ModuleHeaderDescription) feature;
1948                 ModuleResolution_attribute mod =
1949                         (ModuleResolution_attribute) attr;
1950                 header.moduleResolution = mod.resolution_flags;
1951                 break;
1952             }
1953             case Attribute.ModulePackages:
1954             case Attribute.ModuleHashes:
1955                 break;
1956             case Attribute.NestHost: {
1957                 assert feature instanceof ClassHeaderDescription;
1958                 NestHost_attribute nestHost = (NestHost_attribute) attr;
1959                 ClassHeaderDescription chd = (ClassHeaderDescription) feature;
1960                 chd.nestHost = nestHost.getNestTop(cf.constant_pool).getName();
1961                 break;
1962             }
1963             case Attribute.NestMembers: {
1964                 assert feature instanceof ClassHeaderDescription;
1965                 NestMembers_attribute nestMembers = (NestMembers_attribute) attr;
1966                 ClassHeaderDescription chd = (ClassHeaderDescription) feature;
1967                 chd.nestMembers = Arrays.stream(nestMembers.members_indexes)
1968                                         .mapToObj(i -> getClassName(cf, i))
1969                                         .collect(Collectors.toList());
1970                 break;
1971             }
1972             default:
1973                 throw new IllegalStateException("Unhandled attribute: " +
1974                                                 attrName);
1975         }
1976 
1977         return true;
1978     }
1979 
1980     private static String getClassName(ClassFile cf, int idx) {
1981         try {
1982             return cf.constant_pool.getClassInfo(idx).getName();
1983         } catch (InvalidIndex ex) {
1984             throw new IllegalStateException(ex);
1985         } catch (ConstantPool.UnexpectedEntry ex) {
1986             throw new IllegalStateException(ex);
1987         } catch (ConstantPoolException ex) {
1988             throw new IllegalStateException(ex);
1989         }
1990     }
1991 


2732                 }
2733             }
2734         }
2735 
2736         public String packge() {
2737             String pack;
2738             int lastSlash = name.lastIndexOf('/');
2739             if (lastSlash != (-1)) {
2740                 pack = name.substring(0, lastSlash).replace('/', '.');
2741             } else {
2742                 pack = "";
2743             }
2744 
2745             return pack;
2746         }
2747     }
2748 
2749     static class ClassHeaderDescription extends HeaderDescription {
2750         String extendsAttr;
2751         List<String> implementsAttr;
2752         String nestHost;
2753         List<String> nestMembers;
2754 
2755         @Override
2756         public int hashCode() {
2757             int hash = super.hashCode();
2758             hash = 17 * hash + Objects.hashCode(this.extendsAttr);
2759             hash = 17 * hash + Objects.hashCode(this.implementsAttr);
2760             hash = 17 * hash + Objects.hashCode(this.nestHost);
2761             hash = 17 * hash + Objects.hashCode(this.nestMembers);
2762             return hash;
2763         }
2764 
2765         @Override
2766         public boolean equals(Object obj) {
2767             if (obj == null) {
2768                 return false;
2769             }
2770             if (!super.equals(obj)) {
2771                 return false;
2772             }
2773             final ClassHeaderDescription other = (ClassHeaderDescription) obj;
2774             if (!Objects.equals(this.extendsAttr, other.extendsAttr)) {
2775                 return false;
2776             }
2777             if (!Objects.equals(this.implementsAttr, other.implementsAttr)) {
2778                 return false;
2779             }
2780             if (!Objects.equals(this.nestHost, other.nestHost)) {
2781                 return false;
2782             }
2783             if (!Objects.equals(this.nestMembers, other.nestMembers)) {
2784                 return false;
2785             }
2786             return true;
2787         }
2788 
2789         @Override
2790         public void write(Appendable output, String baselineVersion, String version) throws IOException {
2791             if (!versions.contains(version) ||
2792                 (baselineVersion != null && versions.contains(baselineVersion) && versions.contains(version)))
2793                 return ;
2794             output.append("header");
2795             if (extendsAttr != null)
2796                 output.append(" extends " + extendsAttr);
2797             if (implementsAttr != null && !implementsAttr.isEmpty())
2798                 output.append(" implements " + serializeList(implementsAttr));
2799             if (nestHost != null)
2800                 output.append(" nestHost " + nestHost);
2801             if (nestMembers != null && !nestMembers.isEmpty())
2802                 output.append(" nestMembers " + serializeList(nestMembers));
2803             writeAttributes(output);
2804             output.append("\n");
2805             writeInnerClasses(output, baselineVersion, version);
2806         }
2807 
2808         @Override
2809         public boolean read(LineBasedReader reader) throws IOException {
2810             if (!"header".equals(reader.lineKey))
2811                 return false;
2812 
2813             extendsAttr = reader.attributes.get("extends");
2814             String elementsList = reader.attributes.get("implements");
2815             implementsAttr = deserializeList(elementsList);
2816 
2817             nestHost = reader.attributes.get("nestHost");
2818             String nestMembersList = reader.attributes.get("nestMembers");
2819             nestMembers = deserializeList(nestMembersList);
2820 
2821             readAttributes(reader);
2822             reader.moveNext();
2823             readInnerClasses(reader);
2824 
2825             return true;
2826         }
2827 
2828     }
2829 
2830     static abstract class HeaderDescription extends FeatureDescription {
2831         List<InnerClassInfo> innerClasses;
2832 
2833         @Override
2834         public int hashCode() {
2835             int hash = super.hashCode();
2836             hash = 19 * hash + Objects.hashCode(this.innerClasses);
2837             return hash;
2838         }
2839 
2840         @Override


3614 
3615                 ExcludeIncludeList excludeList =
3616                         ExcludeIncludeList.create(args[2]);
3617 
3618                 new CreateSymbols().createBaseLine(versions,
3619                                                    excludeList,
3620                                                    descDest,
3621                                                    args);
3622                 break;
3623             }
3624             case "build-description-incremental": {
3625                 if (args.length != 3) {
3626                     help();
3627                     return ;
3628                 }
3629 
3630                 new CreateSymbols().createIncrementalBaseLine(args[1], args[2], args);
3631                 break;
3632             }
3633             case "build-ctsym":
3634                 if (args.length != 4) {
3635                     help();
3636                     return ;
3637                 }
3638 
3639                 new CreateSymbols().createSymbols(args[1],
3640                                                   args[2],
3641                                                   args[3],
3642                                                   CtSymKind.JOINED_VERSIONS);
3643                 break;
3644         }
3645     }
3646 
3647 }
< prev index next >