< prev index next >

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

Print this page
rev 59492 : [mq]: 8244763-create-symbols
rev 59493 : imported patch 8244763-v2


  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package build.tools.symbolgenerator;
  27 
  28 import build.tools.symbolgenerator.CreateSymbols
  29                                   .ModuleHeaderDescription
  30                                   .ProvidesDescription;
  31 import build.tools.symbolgenerator.CreateSymbols
  32                                   .ModuleHeaderDescription
  33                                   .RequiresDescription;

  34 import java.io.BufferedInputStream;
  35 import java.io.BufferedReader;
  36 import java.io.BufferedOutputStream;
  37 import java.io.ByteArrayInputStream;
  38 import java.io.ByteArrayOutputStream;
  39 import java.io.File;
  40 import java.io.FileOutputStream;
  41 import java.io.IOException;
  42 import java.io.InputStream;
  43 import java.io.OutputStream;
  44 import java.io.StringWriter;
  45 import java.io.Writer;

  46 import java.nio.file.Files;
  47 import java.nio.file.FileVisitResult;
  48 import java.nio.file.FileVisitor;
  49 import java.nio.file.Path;
  50 import java.nio.file.Paths;
  51 import java.nio.file.attribute.BasicFileAttributes;
  52 import java.util.stream.Stream;
  53 import java.util.ArrayList;
  54 import java.util.Arrays;
  55 import java.util.Calendar;
  56 import java.util.Collection;
  57 import java.util.Collections;
  58 import java.util.Comparator;
  59 import java.util.EnumSet;
  60 import java.util.HashMap;
  61 import java.util.HashSet;
  62 import java.util.Iterator;
  63 import java.util.LinkedHashMap;
  64 import java.util.List;
  65 import java.util.Locale;


 203  *     <jdk-7>/bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes
 204  *     <jdk-8>/bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes
 205  *     java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list
 206  *                                                    8 OpenJDK8.classes '<none>'
 207  *                                                    7 OpenJDK7.classes 8
 208  *
 209  * Note: the versions are expected to be a single character.
 210  *
 211  */
 212 public class CreateSymbols {
 213 
 214     //<editor-fold defaultstate="collapsed" desc="ct.sym construction">
 215     /**Create sig files for ct.sym reading the classes description from the directory that contains
 216      * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
 217      */
 218     @SuppressWarnings("unchecked")
 219     public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFile, String ctSymLocation,
 220                               long timestamp, String currentVersion, String systemModules) throws IOException {
 221         LoadDescriptions data = load(ctDescriptionFileExtra != null ? Paths.get(ctDescriptionFileExtra)
 222                                                                     : null,
 223                                      Paths.get(ctDescriptionFile), null);
 224 
 225         splitHeaders(data.classes);
 226 
 227         Map<String, Map<Character, String>> package2Version2Module = new HashMap<>();
 228         Map<String, Set<FileData>> directory2FileData = new TreeMap<>();
 229 
 230         for (ModuleDescription md : data.modules.values()) {
 231             for (ModuleHeaderDescription mhd : md.header) {
 232                 List<String> versionsList =
 233                         Collections.singletonList(mhd.versions);
 234                 writeModulesForVersions(directory2FileData,
 235                                         md,
 236                                         mhd,
 237                                         versionsList);
 238                 mhd.exports.stream().forEach(pkg -> {
 239                     for (char v : mhd.versions.toCharArray()) {
 240                         package2Version2Module.computeIfAbsent(pkg, dummy -> new HashMap<>()).put(v, md.name);
 241                     }
 242                 });
 243             }


 286              ZipOutputStream jos = new ZipOutputStream(bos)) {
 287             for (Entry<String, Set<FileData>> e : directory2FileData.entrySet()) {
 288                 jos.putNextEntry(createZipEntry(e.getKey(), timestamp));
 289                 for (FileData fd : e.getValue()) {
 290                     jos.putNextEntry(createZipEntry(fd.fileName, timestamp));
 291                     jos.write(fd.fileData);
 292                 }
 293             }
 294         }
 295     }
 296 
 297     private ZipEntry createZipEntry(String name, long timestamp) {
 298         ZipEntry ze = new ZipEntry(name);
 299 
 300         ze.setTime(timestamp);
 301         return ze;
 302     }
 303 
 304     public static String EXTENSION = ".sig";
 305 
 306     LoadDescriptions load(Path ctDescriptionWithExtraContent, Path ctDescriptionOpen, String deletePlatform) throws IOException {
 307         Map<String, PlatformInput> platforms = new LinkedHashMap<>();
 308 
 309         if (ctDescriptionWithExtraContent != null && Files.isRegularFile(ctDescriptionWithExtraContent)) {
 310             try (LineBasedReader reader = new LineBasedReader(ctDescriptionWithExtraContent)) {
 311                 while (reader.hasNext()) {
 312                     switch (reader.lineKey) {
 313                         case "generate":
 314                             //ignore
 315                             reader.moveNext();
 316                             break;
 317                         case "platform":
 318                             PlatformInput platform = PlatformInput.load(ctDescriptionWithExtraContent,
 319                                                                         reader);
 320                             if (!platform.version.equals(deletePlatform))
 321                                 platforms.put(platform.version, platform);
 322                             reader.moveNext();
 323                             break;
 324                         default:
 325                             throw new IllegalStateException("Unknown key: " + reader.lineKey);
 326                     }
 327                 }
 328             }
 329         }
 330 
 331         Set<String> generatePlatforms = null;
 332 
 333         try (LineBasedReader reader = new LineBasedReader(ctDescriptionOpen)) {
 334             while (reader.hasNext()) {
 335                 switch (reader.lineKey) {
 336                     case "generate":
 337                         String[] platformsAttr = reader.attributes.get("platforms").split(":");
 338                         generatePlatforms = new HashSet<>(List.of(platformsAttr));
 339                         generatePlatforms.remove(deletePlatform);
 340                         reader.moveNext();
 341                         break;
 342                     case "platform":
 343                         PlatformInput platform = PlatformInput.load(ctDescriptionOpen, reader);
 344                         if (!platform.version.equals(deletePlatform) &&
 345                             !platforms.containsKey(platform.version))
 346                             platforms.put(platform.version, platform);
 347                         reader.moveNext();
 348                         break;
 349                     default:
 350                         throw new IllegalStateException("Unknown key: " + reader.lineKey);
 351                 }
 352             }
 353         }
 354 
 355         Map<String, ClassDescription> classes = new LinkedHashMap<>();
 356         Map<String, ModuleDescription> modules = new LinkedHashMap<>();
 357 
 358         for (PlatformInput platform : platforms.values()) {
 359             for (ClassDescription cd : classes.values()) {
 360                 addNewVersion(cd.header, platform.basePlatform, platform.version);
 361                 addNewVersion(cd.fields, platform.basePlatform, platform.version);
 362                 addNewVersion(cd.methods, platform.basePlatform, platform.version);
 363             }
 364             for (ModuleDescription md : modules.values()) {
 365                 addNewVersion(md.header, platform.basePlatform, platform.version);


 391                                         platform.version);
 392                                 break;
 393                             }
 394                             case "-module": {
 395                                 ModuleDescription md =
 396                                         modules.computeIfAbsent(nameAttr,
 397                                                 n -> new ModuleDescription());
 398                                 removeVersion(md.header, h -> true,
 399                                               platform.version);
 400                                 reader.moveNext();
 401                                 break;
 402                             }
 403                         }
 404                     }
 405                 }
 406             }
 407         }
 408 
 409         ClassList result = new ClassList();
 410 
 411         for (ClassDescription desc : classes.values()) {








 412             Iterator<ClassHeaderDescription> chdIt = desc.header.iterator();
 413 
 414             while (chdIt.hasNext()) {
 415                 ClassHeaderDescription chd = chdIt.next();
 416 
 417                 chd.versions = reduce(chd.versions, generatePlatforms);
 418                 if (chd.versions.isEmpty())
 419                     chdIt.remove();
 420             }

 421 
 422             if (desc.header.isEmpty()) {

 423                 continue;
 424             }
 425 
 426             Iterator<MethodDescription> methodIt = desc.methods.iterator();
 427 
 428             while (methodIt.hasNext()) {
 429                 MethodDescription method = methodIt.next();
 430 
 431                 method.versions = reduce(method.versions, generatePlatforms);
 432                 if (method.versions.isEmpty())
 433                     methodIt.remove();
 434             }
 435 
 436             Iterator<FieldDescription> fieldIt = desc.fields.iterator();
 437 
 438             while (fieldIt.hasNext()) {
 439                 FieldDescription field = fieldIt.next();
 440 
 441                 field.versions = reduce(field.versions, generatePlatforms);
 442                 if (field.versions.isEmpty())
 443                     fieldIt.remove();
 444             }
 445 
 446             result.add(desc);
 447         }
 448 
 449         Map<String, ModuleDescription> moduleList = new HashMap<>();
 450 
 451         for (ModuleDescription desc : modules.values()) {
 452             Iterator<ModuleHeaderDescription> mhdIt = desc.header.iterator();
 453 
 454             while (mhdIt.hasNext()) {
 455                 ModuleHeaderDescription mhd = mhdIt.next();
 456 
 457                 mhd.versions = reduce(mhd.versions, generatePlatforms);
 458                 if (mhd.versions.isEmpty())
 459                     mhdIt.remove();
 460             }
 461 
 462             if (desc.header.isEmpty()) {

 463                 continue;
 464             }
 465 
 466             moduleList.put(desc.name, desc);
 467         }
 468 
 469         return new LoadDescriptions(result,
 470                                     moduleList,
 471                                     new ArrayList<>(platforms.values()));
 472     }
 473 
 474     static final class LoadDescriptions {
 475         public final ClassList classes;
 476         public final Map<String, ModuleDescription> modules;
 477         public final List<PlatformInput> versions;
 478 
 479         public LoadDescriptions(ClassList classes,
 480                                 Map<String, ModuleDescription>  modules,
 481                                 List<PlatformInput> versions) {
 482             this.classes = classes;
 483             this.modules = modules;
 484             this.versions = versions;
 485         }
 486 
 487     }
 488 
 489     static final class LineBasedReader implements AutoCloseable {
 490         private final BufferedReader input;
 491         public String lineKey;


 533         Set<String> otherSet = new HashSet<>();
 534 
 535         for (char v : other.toCharArray()) {
 536             otherSet.add("" + v);
 537         }
 538 
 539         return reduce(original, otherSet);
 540     }
 541 
 542     private static String reduce(String original, Set<String> generate) {
 543         StringBuilder sb = new StringBuilder();
 544 
 545         for (char v : original.toCharArray()) {
 546             if (generate.contains("" + v)) {
 547                 sb.append(v);
 548             }
 549         }
 550         return sb.toString();
 551     }
 552 











 553     private static class PlatformInput {
 554         public final String version;
 555         public final String basePlatform;
 556         public final List<String> files;
 557         public final Path ctDescription;
 558         public PlatformInput(Path ctDescription, String version, String basePlatform, List<String> files) {
 559             this.ctDescription = ctDescription;
 560             this.version = version;
 561             this.basePlatform = basePlatform;
 562             this.files = files;
 563         }
 564 
 565         public static PlatformInput load(Path ctDescription, LineBasedReader in) throws IOException {
 566             return new PlatformInput(ctDescription,
 567                                      in.attributes.get("version"),
 568                                      in.attributes.get("base"),
 569                                      List.of(in.attributes.get("files").split(":")));
 570         }
 571     }
 572 


1241                     return i;
1242                 }
1243             }
1244             i++;
1245         }
1246 
1247         return addToCP(constantPool, new CONSTANT_Class_info(null, classNameIndex));
1248     }
1249     //</editor-fold>
1250     //</editor-fold>
1251 
1252     //<editor-fold defaultstate="collapsed" desc="Create Symbol Description">
1253     public void createBaseLine(List<VersionDescription> versions,
1254                                ExcludeIncludeList excludesIncludes,
1255                                Path descDest,
1256                                String[] args) throws IOException {
1257         ClassList classes = new ClassList();
1258         Map<String, ModuleDescription> modules = new HashMap<>();
1259 
1260         for (VersionDescription desc : versions) {
1261             List<byte[]> classFileData = new ArrayList<>();
1262 
1263             try (BufferedReader descIn =
1264                     Files.newBufferedReader(Paths.get(desc.classes))) {
1265                 String line;
1266                 while ((line = descIn.readLine()) != null) {
1267                     ByteArrayOutputStream data = new ByteArrayOutputStream();
1268                     for (int i = 0; i < line.length(); i += 2) {
1269                         String hex = line.substring(i, i + 2);
1270                         data.write(Integer.parseInt(hex, 16));
1271                     }
1272                     classFileData.add(data.toByteArray());
1273                 }
1274             } catch (IOException ex) {
1275                 throw new IllegalStateException(ex);
1276             }
1277 
1278             loadVersionClasses(classes, modules, classFileData, excludesIncludes, desc.version);
1279         }
1280 
1281         List<PlatformInput> platforms =
1282                 versions.stream()
1283                         .map(desc -> new PlatformInput(null,
1284                                                        desc.version,
1285                                                        desc.primaryBaseline,
1286                                                        null))
1287                         .collect(Collectors.toList());
1288 
1289         dumpDescriptions(classes, modules, platforms, descDest.resolve("symbols"), args);
1290     }
1291     //where:
1292         private static final String DO_NO_MODIFY =
1293             "#\n" +
1294             "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" +
1295             "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" +
1296             "#\n" +
1297             "# This code is free software; you can redistribute it and/or modify it\n" +
1298             "# under the terms of the GNU General Public License version 2 only, as\n" +
1299             "# published by the Free Software Foundation.  Oracle designates this\n" +
1300             "# particular file as subject to the \"Classpath\" exception as provided\n" +
1301             "# by Oracle in the LICENSE file that accompanied this code.\n" +
1302             "#\n" +
1303             "# This code is distributed in the hope that it will be useful, but WITHOUT\n" +
1304             "# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +
1305             "# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n" +
1306             "# version 2 for more details (a copy is included in the LICENSE file that\n" +
1307             "# accompanied this code).\n" +
1308             "#\n" +
1309             "# You should have received a copy of the GNU General Public License version\n" +
1310             "# 2 along with this work; if not, write to the Free Software Foundation,\n" +
1311             "# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n" +
1312             "#\n" +
1313             "# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n" +
1314             "# or visit www.oracle.com if you need additional information or have any\n" +
1315             "# questions.\n" +
1316             "#\n" +
1317             "# ##########################################################\n" +
1318             "# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ###\n" +
1319             "# ##########################################################\n" +
1320             "#\n";
1321 





















1322     private void loadVersionClasses(ClassList classes,
1323                                     Map<String, ModuleDescription> modules,
1324                                     Iterable<byte[]> classData,
1325                                     ExcludeIncludeList excludesIncludes,
1326                                     String version) {

1327         Map<String, ModuleDescription> currentVersionModules =
1328                 new HashMap<>();
1329 
1330         for (byte[] classFileData : classData) {
1331             try (InputStream in = new ByteArrayInputStream(classFileData)) {
1332                 inspectModuleInfoClassFile(in,
1333                                            currentVersionModules, version);
1334             } catch (IOException | ConstantPoolException ex) {
1335                 throw new IllegalStateException(ex);
1336             }
1337         }
1338 
1339         ExcludeIncludeList currentEIList = excludesIncludes;
1340 
1341         if (!currentVersionModules.isEmpty()) {
1342             Set<String> includes = new HashSet<>();
1343 
1344             for (ModuleDescription md : currentVersionModules.values()) {
1345                 md.header.get(0).exports.stream().map(e -> e + '/')
1346                                         .forEach(includes::add);


1430                 while(nestMemberIt.hasNext()) {
1431                     String member = nestMemberIt.next();
1432                     if (!includedClasses.contains(member))
1433                         nestMemberIt.remove();
1434                 }
1435             }
1436 
1437             if (header.innerClasses != null) {
1438                 Iterator<InnerClassInfo> innerClassIt = header.innerClasses.iterator();
1439 
1440                 while(innerClassIt.hasNext()) {
1441                     InnerClassInfo ici = innerClassIt.next();
1442                     if (!includedClasses.contains(ici.innerClass))
1443                         innerClassIt.remove();
1444                 }
1445             }
1446 
1447             ClassDescription existing = classes.find(clazz.name, true);
1448 
1449             if (existing != null) {
1450                 addClassHeader(existing, header, version);
1451                 for (MethodDescription currentMethod : clazz.methods) {
1452                     addMethod(existing, currentMethod, version);
1453                 }
1454                 for (FieldDescription currentField : clazz.fields) {
1455                     addField(existing, currentField, version);
1456                 }
1457             } else {
1458                 classes.add(clazz);
1459             }
1460         }
1461 
1462         for (ModuleDescription module : currentVersionModules.values()) {
1463             ModuleHeaderDescription header = module.header.get(0);
1464 
1465             if (header.innerClasses != null) {
1466                 Iterator<InnerClassInfo> innerClassIt =
1467                         header.innerClasses.iterator();
1468 
1469                 while(innerClassIt.hasNext()) {
1470                     InnerClassInfo ici = innerClassIt.next();
1471                     if (!includedClasses.contains(ici.innerClass))
1472                         innerClassIt.remove();
1473                 }
1474             }
1475 
1476             ModuleDescription existing = modules.get(module.name);
1477 
1478             if (existing != null) {
1479                 addModuleHeader(existing, header, version);
1480             } else {
1481                 modules.put(module.name, module);
1482             }
1483         }
1484     }
1485     //where:
1486         private static final String PROPERITARY_ANNOTATION =
1487                 "Lsun/Proprietary+Annotation;";
1488 
1489     private void dumpDescriptions(ClassList classes,
1490                                   Map<String, ModuleDescription> modules,
1491                                   List<PlatformInput> versions,

1492                                   Path ctDescriptionFile,
1493                                   String[] args) throws IOException {
1494         classes.sort();
1495 
1496         Map<String, String> package2Modules = new HashMap<>();
1497 
1498         versions.stream()
1499                 .filter(v -> "9".compareTo(v.version) <= 0)
1500                 .sorted((v1, v2) -> v1.version.compareTo(v2.version))
1501                 .forEach(v -> {
1502             for (ModuleDescription md : modules.values()) {
1503                 md.header
1504                   .stream()
1505                   .filter(h -> h.versions.contains(v.version))
1506                   .flatMap(h -> h.exports.stream())
1507                   .map(p -> p.replace('/', '.'))
1508                   .forEach(p -> package2Modules.putIfAbsent(p, md.name));
1509             }
1510         });
1511 


1538             module2Classes.computeIfAbsent(module, m -> new ArrayList<>())
1539                     .add(clazz);
1540         }
1541 
1542         modules.keySet()
1543                .stream()
1544                .filter(m -> !module2Classes.containsKey(m))
1545                .forEach(m -> module2Classes.put(m, Collections.emptyList()));
1546 
1547         Files.createDirectories(ctDescriptionFile.getParent());
1548 
1549         int year = Calendar.getInstance(TimeZone.getTimeZone("UTF"), Locale.ROOT)
1550                            .get(Calendar.YEAR);
1551 
1552         try (Writer symbolsOut = Files.newBufferedWriter(ctDescriptionFile)) {
1553             Map<PlatformInput, List<String>> outputFiles = new LinkedHashMap<>();
1554 
1555             for (PlatformInput desc : versions) {
1556                 List<String> files = desc.files;
1557 
1558                 if (files == null) {
1559                     files = new ArrayList<>();
1560                     for (Entry<String, List<ClassDescription>> e : module2Classes.entrySet()) {
1561                         StringWriter data = new StringWriter();
1562                         ModuleDescription module = modules.get(e.getKey());
1563 
1564                         module.write(data, desc.basePlatform, desc.version);
1565 
1566                         for (ClassDescription clazz : e.getValue()) {
1567                             clazz.write(data, desc.basePlatform, desc.version);
1568                         }
1569 
1570                         String fileName = e.getKey() + "-" + desc.version + ".sym.txt";
1571                         Path f = ctDescriptionFile.getParent().resolve(fileName);
1572 
1573                         String dataString = data.toString();
1574 
1575                         if (!dataString.isEmpty()) {
1576                             try (Writer out = Files.newBufferedWriter(f)) {
1577                                 out.append(DO_NO_MODIFY.replace("{YEAR}", String.valueOf(year)));























1578                                 out.write(dataString);
1579                             }

1580                             files.add(f.getFileName().toString());
1581                         }
1582                     }
1583                 }
1584 
1585                 outputFiles.put(desc, files);
1586             }
1587             symbolsOut.append(DO_NO_MODIFY.replace("{YEAR}", "2015, " + year));
1588             symbolsOut.append("#command used to generate this file:\n");
1589             symbolsOut.append("#")
1590                       .append(CreateSymbols.class.getName())
1591                       .append(" ")
1592                       .append(Arrays.stream(args)
1593                                     .collect(Collectors.joining(" ")))
1594                       .append("\n");
1595             symbolsOut.append("#\n");
1596             symbolsOut.append("generate platforms ")
1597                       .append(versions.stream()
1598                                       .map(v -> v.version)
1599                                       .sorted()
1600                                       .collect(Collectors.joining(":")))
1601                       .append("\n");
1602             for (Entry<PlatformInput, List<String>> versionFileEntry : outputFiles.entrySet()) {
1603                 symbolsOut.append("platform version ")
1604                           .append(versionFileEntry.getKey().version);
1605                 if (versionFileEntry.getKey().basePlatform != null) {
1606                     symbolsOut.append(" base ")
1607                               .append(versionFileEntry.getKey().basePlatform);
1608                 }
1609                 symbolsOut.append(" files ")
1610                           .append(versionFileEntry.getValue()
1611                                                   .stream()
1612                                                   .map(p -> p)
1613                                                   .sorted()
1614                                                   .collect(Collectors.joining(":")))
1615                           .append("\n");
1616             }
1617         }
1618     }
1619 
1620     public void createIncrementalBaseLine(String ctDescriptionFile,
1621                                           String excludeFile,



1622                                           String[] args) throws IOException {
1623         String specVersion = System.getProperty("java.specification.version");
1624         String currentVersion =
1625                 Integer.toString(Integer.parseInt(specVersion), Character.MAX_RADIX);
1626         currentVersion = currentVersion.toUpperCase(Locale.ROOT);
1627         Path ctDescriptionPath = Paths.get(ctDescriptionFile).toAbsolutePath();
1628         LoadDescriptions data = load(null, ctDescriptionPath, currentVersion);
1629 
1630         ClassList classes = data.classes;
1631         Map<String, ModuleDescription> modules = data.modules;
1632         List<PlatformInput> versions = data.versions;
1633 
1634         ExcludeIncludeList excludeList =
1635                 ExcludeIncludeList.create(excludeFile);
1636 
1637         Iterable<byte[]> classBytes = dumpCurrentClasses();
1638         loadVersionClasses(classes, modules, classBytes, excludeList, currentVersion);

























1639 
1640         String baseline;

















1641 
1642         if (versions.isEmpty()) {
1643             baseline = null;






1644         } else {
1645             baseline = versions.stream()
1646                                .sorted((v1, v2) -> v2.version.compareTo(v1.version))
1647                                .findFirst()
1648                                .get()
1649                                .version;
1650         }
1651 
1652         versions.add(new PlatformInput(null, currentVersion, baseline, null));
1653         dumpDescriptions(classes, modules, versions, ctDescriptionPath, args);
1654     }
1655 
1656     private List<byte[]> dumpCurrentClasses() throws IOException {
1657         JavacTool tool = JavacTool.create();
1658         Context ctx = new Context();
1659         String version = System.getProperty("java.specification.version");
1660         JavacTask task = tool.getTask(null, null, null,
1661                                       List.of("--release", version),
1662                                       null, null, ctx);
1663         task.getElements().getTypeElement("java.lang.Object");
1664         JavaFileManager fm = ctx.get(JavaFileManager.class);
1665 
1666         List<byte[]> data = new ArrayList<>();
1667         for (Location modLoc : LOCATIONS) {
1668             for (Set<JavaFileManager.Location> module :
1669                     fm.listLocationsForModules(modLoc)) {
1670                 for (JavaFileManager.Location loc : module) {
1671                     Iterable<JavaFileObject> files =
1672                             fm.list(loc,
1673                                     "",


1727         for (Attribute attr : cf.attributes) {
1728             if (!readAttribute(cf, headerDesc, attr))
1729                 return ;
1730         }
1731 
1732         ClassDescription clazzDesc = null;
1733 
1734         for (ClassDescription cd : classes) {
1735             if (cd.name.equals(cf.getName())) {
1736                 clazzDesc = cd;
1737                 break;
1738             }
1739         }
1740 
1741         if (clazzDesc == null) {
1742             clazzDesc = new ClassDescription();
1743             clazzDesc.name = cf.getName();
1744             classes.add(clazzDesc);
1745         }
1746 
1747         addClassHeader(clazzDesc, headerDesc, version);
1748 
1749         for (Method m : cf.methods) {
1750             if (!include(m.access_flags.flags))
1751                 continue;
1752             MethodDescription methDesc = new MethodDescription();
1753             methDesc.flags = m.access_flags.flags;
1754             methDesc.name = m.getName(cf.constant_pool);
1755             methDesc.descriptor = m.descriptor.getValue(cf.constant_pool);
1756             for (Attribute attr : m.attributes) {
1757                 readAttribute(cf, methDesc, attr);
1758             }
1759             addMethod(clazzDesc, methDesc, version);
1760         }
1761         for (Field f : cf.fields) {
1762             if (!include(f.access_flags.flags))
1763                 continue;
1764             FieldDescription fieldDesc = new FieldDescription();
1765             fieldDesc.flags = f.access_flags.flags;
1766             fieldDesc.name = f.getName(cf.constant_pool);
1767             fieldDesc.descriptor = f.descriptor.getValue(cf.constant_pool);
1768             for (Attribute attr : f.attributes) {
1769                 readAttribute(cf, fieldDesc, attr);
1770             }
1771             addField(clazzDesc, fieldDesc, version);
1772         }
1773     }
1774 
1775     private void inspectModuleInfoClassFile(InputStream in,
1776             Map<String, ModuleDescription> modules,
1777             String version) throws IOException, ConstantPoolException {
1778         ClassFile cf = ClassFile.read(in);
1779 
1780         if (!cf.access_flags.is(AccessFlags.ACC_MODULE)) {
1781             return ;
1782         }
1783 
1784         ModuleHeaderDescription headerDesc = new ModuleHeaderDescription();
1785 
1786         headerDesc.versions = version;
1787         headerDesc.flags = cf.access_flags.flags;
1788 
1789         for (Attribute attr : cf.attributes) {
1790             if (!readAttribute(cf, headerDesc, attr))
1791                 return ;


1810         //normalize:
1811         boolean existed = false;
1812         for (ModuleHeaderDescription existing : moduleDesc.header) {
1813             if (existing.equals(headerDesc)) {
1814                 headerDesc = existing;
1815                 existed = true;
1816             }
1817         }
1818 
1819         headerDesc.versions += version;
1820 
1821         if (!existed) {
1822             moduleDesc.header.add(headerDesc);
1823         }
1824     }
1825 
1826     private boolean include(int accessFlags) {
1827         return (accessFlags & (AccessFlags.ACC_PUBLIC | AccessFlags.ACC_PROTECTED)) != 0;
1828     }
1829 
1830     private void addClassHeader(ClassDescription clazzDesc, ClassHeaderDescription headerDesc, String version) {
1831         //normalize:
1832         boolean existed = false;
1833         for (ClassHeaderDescription existing : clazzDesc.header) {
1834             if (existing.equals(headerDesc)) {
1835                 headerDesc = existing;
1836                 existed = true;
1837             }
1838         }
1839 
1840         if (!existed) {
1841             //check if the only difference between the 7 and 8 version is the Profile annotation
1842             //if so, copy it to the pre-8 version, so save space
1843             for (ClassHeaderDescription existing : clazzDesc.header) {
1844                 List<AnnotationDescription> annots = existing.classAnnotations;
1845 
1846                 if (annots != null) {
1847                     for (AnnotationDescription ad : annots) {
1848                         if (PROFILE_ANNOTATION.equals(ad.annotationType)) {
1849                             existing.classAnnotations = new ArrayList<>(annots);
1850                             existing.classAnnotations.remove(ad);
1851                             if (existing.equals(headerDesc)) {
1852                                 headerDesc = existing;
1853                                 existed = true;
1854                             }
1855                             existing.classAnnotations = annots;
1856                             break;
1857                         }
1858                     }
1859                 }
1860             }
1861         }
1862 
1863         headerDesc.versions += version;
1864 
1865         if (!existed) {
1866             clazzDesc.header.add(headerDesc);
1867         }
1868     }
1869 
1870     private void addMethod(ClassDescription clazzDesc, MethodDescription methDesc, String version) {
1871         //normalize:
1872         boolean methodExisted = false;
1873         for (MethodDescription existing : clazzDesc.methods) {
1874             if (existing.equals(methDesc)) {
1875                 methodExisted = true;
1876                 methDesc = existing;
1877                 break;
1878             }
1879         }
1880         methDesc.versions += version;
1881         if (!methodExisted) {
1882             clazzDesc.methods.add(methDesc);
1883         }
1884     }
1885 
1886     private void addField(ClassDescription clazzDesc, FieldDescription fieldDesc, String version) {
1887         boolean fieldExisted = false;
1888         for (FieldDescription existing : clazzDesc.fields) {
1889             if (existing.equals(fieldDesc)) {
1890                 fieldExisted = true;
1891                 fieldDesc = existing;
1892                 break;
1893             }
1894         }
1895         fieldDesc.versions += version;
1896         if (!fieldExisted) {
1897             clazzDesc.fields.add(fieldDesc);
1898         }
1899     }
1900 
1901     private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribute attr) throws ConstantPoolException {
1902         String attrName = attr.getName(cf.constant_pool);
1903         switch (attrName) {
1904             case Attribute.AnnotationDefault:
1905                 assert feature instanceof MethodDescription;
1906                 element_value defaultValue = ((AnnotationDefault_attribute) attr).default_value;
1907                 ((MethodDescription) feature).annotationDefaultValue =
1908                         convertElementValue(cf.constant_pool, defaultValue);
1909                 break;
1910             case "Deprecated":
1911                 feature.deprecated = true;
1912                 break;


2281         }
2282 
2283         private static boolean matches(Set<String> list, String className) {
2284             if (list.contains(className))
2285                 return true;
2286             String pack = className.substring(0, className.lastIndexOf('/') + 1);
2287             return list.contains(pack);
2288         }
2289     }
2290     //</editor-fold>
2291 
2292     //<editor-fold defaultstate="collapsed" desc="Class Data Structures">
2293     static boolean checkChange(String versions, String version,
2294                                String baselineVersion) {
2295         return versions.contains(version) ^
2296                (baselineVersion != null &&
2297                 versions.contains(baselineVersion));
2298     }
2299 
2300     static abstract class FeatureDescription {

2301         int flags;
2302         boolean deprecated;
2303         String signature;
2304         String versions = "";
2305         List<AnnotationDescription> classAnnotations;
2306         List<AnnotationDescription> runtimeAnnotations;
2307 
2308         protected void writeAttributes(Appendable output) throws IOException {
2309             if (flags != 0)
2310                 output.append(" flags " + Integer.toHexString(flags));
2311             if (deprecated) {
2312                 output.append(" deprecated true");
2313             }
2314             if (signature != null) {
2315                 output.append(" signature " + quote(signature, false));
2316             }
2317             if (classAnnotations != null && !classAnnotations.isEmpty()) {
2318                 output.append(" classAnnotations ");
2319                 for (AnnotationDescription a : classAnnotations) {
2320                     output.append(quote(a.toString(), false));


2345             String inDeprecated = reader.attributes.get("deprecated");
2346             if ("true".equals(inDeprecated)) {
2347                 deprecated = true;
2348             }
2349             signature = reader.attributes.get("signature");
2350             String inClassAnnotations = reader.attributes.get("classAnnotations");
2351             if (inClassAnnotations != null) {
2352                 classAnnotations = parseAnnotations(inClassAnnotations, new int[1]);
2353             }
2354             String inRuntimeAnnotations = reader.attributes.get("runtimeAnnotations");
2355             if (inRuntimeAnnotations != null) {
2356                 runtimeAnnotations = parseAnnotations(inRuntimeAnnotations, new int[1]);
2357             }
2358         }
2359 
2360         public abstract boolean read(LineBasedReader reader) throws IOException;
2361 
2362         @Override
2363         public int hashCode() {
2364             int hash = 3;
2365             hash = 89 * hash + this.flags;
2366             hash = 89 * hash + (this.deprecated ? 1 : 0);
2367             hash = 89 * hash + Objects.hashCode(this.signature);
2368             hash = 89 * hash + listHashCode(this.classAnnotations);
2369             hash = 89 * hash + listHashCode(this.runtimeAnnotations);
2370             return hash;
2371         }
2372 
2373         @Override
2374         public boolean equals(Object obj) {
2375             if (obj == null) {
2376                 return false;
2377             }
2378             if (getClass() != obj.getClass()) {
2379                 return false;
2380             }
2381             final FeatureDescription other = (FeatureDescription) obj;
2382             if (this.flags != other.flags) {
2383                 return false;
2384             }
2385             if (this.deprecated != other.deprecated) {
2386                 return false;
2387             }
2388             if (!Objects.equals(this.signature, other.signature)) {
2389                 return false;
2390             }
2391             if (!listEquals(this.classAnnotations, other.classAnnotations)) {
2392                 return false;
2393             }
2394             if (!listEquals(this.runtimeAnnotations, other.runtimeAnnotations)) {
2395                 return false;
2396             }
2397             return true;
2398         }
2399 
2400     }
2401 
2402     public static class ModuleDescription {


3014             while ("innerclass".equals(reader.lineKey)) {
3015                 InnerClassInfo info = new InnerClassInfo();
3016 
3017                 info.innerClass = reader.attributes.get("innerClass");
3018                 info.outerClass = reader.attributes.get("outerClass");
3019                 info.innerClassName = reader.attributes.get("innerClassName");
3020 
3021                 String inFlags = reader.attributes.get("flags");
3022                 if (inFlags != null && !inFlags.isEmpty())
3023                     info.innerClassFlags = Integer.parseInt(inFlags, 16);
3024 
3025                 innerClasses.add(info);
3026 
3027                 reader.moveNext();
3028             }
3029         }
3030 
3031     }
3032 
3033     static class MethodDescription extends FeatureDescription {

3034         String name;
3035         String descriptor;
3036         List<String> thrownTypes;
3037         Object annotationDefaultValue;
3038         List<List<AnnotationDescription>> classParameterAnnotations;
3039         List<List<AnnotationDescription>> runtimeParameterAnnotations;
3040 




3041         @Override
3042         public int hashCode() {
3043             int hash = super.hashCode();
3044             hash = 59 * hash + Objects.hashCode(this.name);
3045             hash = 59 * hash + Objects.hashCode(this.descriptor);
3046             hash = 59 * hash + Objects.hashCode(this.thrownTypes);
3047             hash = 59 * hash + Objects.hashCode(this.annotationDefaultValue);
3048             return hash;
3049         }
3050 
3051         @Override
3052         public boolean equals(Object obj) {
3053             if (obj == null) {
3054                 return false;
3055             }
3056             if (!super.equals(obj)) {
3057                 return false;
3058             }
3059             final MethodDescription other = (MethodDescription) obj;
3060             if (!Objects.equals(this.name, other.name)) {


3743                         Files.delete(file);
3744                         return FileVisitResult.CONTINUE;
3745                     }
3746                     @Override
3747                     public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
3748                         return FileVisitResult.CONTINUE;
3749                     }
3750                     @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
3751                         Files.delete(dir);
3752                         return FileVisitResult.CONTINUE;
3753                     }
3754                 });
3755 
3756                 ExcludeIncludeList excludeList =
3757                         ExcludeIncludeList.create(args[2]);
3758 
3759                 new CreateSymbols().createBaseLine(versions,
3760                                                    excludeList,
3761                                                    descDest,
3762                                                    args);


















3763                 break;
3764             }
3765             case "build-description-incremental": {
3766                 if (args.length != 3) {
3767                     help();
3768                     return ;
3769                 }
3770 
3771                 new CreateSymbols().createIncrementalBaseLine(args[1], args[2], args);
3772                 break;
3773             }
3774             case "build-ctsym":
3775                 String ctDescriptionFileExtra;
3776                 String ctDescriptionFile;
3777                 String ctSymLocation;
3778                 String timestampSpec;
3779                 String currentVersion;
3780                 String systemModules;
3781 
3782                 if (args.length == 6) {




  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package build.tools.symbolgenerator;
  27 
  28 import build.tools.symbolgenerator.CreateSymbols
  29                                   .ModuleHeaderDescription
  30                                   .ProvidesDescription;
  31 import build.tools.symbolgenerator.CreateSymbols
  32                                   .ModuleHeaderDescription
  33                                   .RequiresDescription;
  34 
  35 import java.io.BufferedInputStream;
  36 import java.io.BufferedReader;
  37 import java.io.BufferedOutputStream;
  38 import java.io.ByteArrayInputStream;
  39 import java.io.ByteArrayOutputStream;
  40 import java.io.File;
  41 import java.io.FileOutputStream;
  42 import java.io.IOException;
  43 import java.io.InputStream;
  44 import java.io.OutputStream;
  45 import java.io.StringWriter;
  46 import java.io.Writer;
  47 import java.nio.charset.StandardCharsets;
  48 import java.nio.file.Files;
  49 import java.nio.file.FileVisitResult;
  50 import java.nio.file.FileVisitor;
  51 import java.nio.file.Path;
  52 import java.nio.file.Paths;
  53 import java.nio.file.attribute.BasicFileAttributes;
  54 import java.util.stream.Stream;
  55 import java.util.ArrayList;
  56 import java.util.Arrays;
  57 import java.util.Calendar;
  58 import java.util.Collection;
  59 import java.util.Collections;
  60 import java.util.Comparator;
  61 import java.util.EnumSet;
  62 import java.util.HashMap;
  63 import java.util.HashSet;
  64 import java.util.Iterator;
  65 import java.util.LinkedHashMap;
  66 import java.util.List;
  67 import java.util.Locale;


 205  *     <jdk-7>/bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes
 206  *     <jdk-8>/bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes
 207  *     java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list
 208  *                                                    8 OpenJDK8.classes '<none>'
 209  *                                                    7 OpenJDK7.classes 8
 210  *
 211  * Note: the versions are expected to be a single character.
 212  *
 213  */
 214 public class CreateSymbols {
 215 
 216     //<editor-fold defaultstate="collapsed" desc="ct.sym construction">
 217     /**Create sig files for ct.sym reading the classes description from the directory that contains
 218      * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
 219      */
 220     @SuppressWarnings("unchecked")
 221     public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFile, String ctSymLocation,
 222                               long timestamp, String currentVersion, String systemModules) throws IOException {
 223         LoadDescriptions data = load(ctDescriptionFileExtra != null ? Paths.get(ctDescriptionFileExtra)
 224                                                                     : null,
 225                                      Paths.get(ctDescriptionFile));
 226 
 227         splitHeaders(data.classes);
 228 
 229         Map<String, Map<Character, String>> package2Version2Module = new HashMap<>();
 230         Map<String, Set<FileData>> directory2FileData = new TreeMap<>();
 231 
 232         for (ModuleDescription md : data.modules.values()) {
 233             for (ModuleHeaderDescription mhd : md.header) {
 234                 List<String> versionsList =
 235                         Collections.singletonList(mhd.versions);
 236                 writeModulesForVersions(directory2FileData,
 237                                         md,
 238                                         mhd,
 239                                         versionsList);
 240                 mhd.exports.stream().forEach(pkg -> {
 241                     for (char v : mhd.versions.toCharArray()) {
 242                         package2Version2Module.computeIfAbsent(pkg, dummy -> new HashMap<>()).put(v, md.name);
 243                     }
 244                 });
 245             }


 288              ZipOutputStream jos = new ZipOutputStream(bos)) {
 289             for (Entry<String, Set<FileData>> e : directory2FileData.entrySet()) {
 290                 jos.putNextEntry(createZipEntry(e.getKey(), timestamp));
 291                 for (FileData fd : e.getValue()) {
 292                     jos.putNextEntry(createZipEntry(fd.fileName, timestamp));
 293                     jos.write(fd.fileData);
 294                 }
 295             }
 296         }
 297     }
 298 
 299     private ZipEntry createZipEntry(String name, long timestamp) {
 300         ZipEntry ze = new ZipEntry(name);
 301 
 302         ze.setTime(timestamp);
 303         return ze;
 304     }
 305 
 306     public static String EXTENSION = ".sig";
 307 
 308     LoadDescriptions load(Path ctDescriptionWithExtraContent, Path ctDescriptionOpen) throws IOException {
 309         Map<String, PlatformInput> platforms = new LinkedHashMap<>();
 310 
 311         if (ctDescriptionWithExtraContent != null && Files.isRegularFile(ctDescriptionWithExtraContent)) {
 312             try (LineBasedReader reader = new LineBasedReader(ctDescriptionWithExtraContent)) {
 313                 while (reader.hasNext()) {
 314                     switch (reader.lineKey) {
 315                         case "generate":
 316                             //ignore
 317                             reader.moveNext();
 318                             break;
 319                         case "platform":
 320                             PlatformInput platform = PlatformInput.load(ctDescriptionWithExtraContent,
 321                                                                         reader);

 322                             platforms.put(platform.version, platform);
 323                             reader.moveNext();
 324                             break;
 325                         default:
 326                             throw new IllegalStateException("Unknown key: " + reader.lineKey);
 327                     }
 328                 }
 329             }
 330         }
 331 
 332         Set<String> generatePlatforms = null;
 333 
 334         try (LineBasedReader reader = new LineBasedReader(ctDescriptionOpen)) {
 335             while (reader.hasNext()) {
 336                 switch (reader.lineKey) {
 337                     case "generate":
 338                         String[] platformsAttr = reader.attributes.get("platforms").split(":");
 339                         generatePlatforms = new HashSet<>(List.of(platformsAttr));

 340                         reader.moveNext();
 341                         break;
 342                     case "platform":
 343                         PlatformInput platform = PlatformInput.load(ctDescriptionOpen, reader);
 344                         if (!platforms.containsKey(platform.version))

 345                             platforms.put(platform.version, platform);
 346                         reader.moveNext();
 347                         break;
 348                     default:
 349                         throw new IllegalStateException("Unknown key: " + reader.lineKey);
 350                 }
 351             }
 352         }
 353 
 354         Map<String, ClassDescription> classes = new LinkedHashMap<>();
 355         Map<String, ModuleDescription> modules = new LinkedHashMap<>();
 356 
 357         for (PlatformInput platform : platforms.values()) {
 358             for (ClassDescription cd : classes.values()) {
 359                 addNewVersion(cd.header, platform.basePlatform, platform.version);
 360                 addNewVersion(cd.fields, platform.basePlatform, platform.version);
 361                 addNewVersion(cd.methods, platform.basePlatform, platform.version);
 362             }
 363             for (ModuleDescription md : modules.values()) {
 364                 addNewVersion(md.header, platform.basePlatform, platform.version);


 390                                         platform.version);
 391                                 break;
 392                             }
 393                             case "-module": {
 394                                 ModuleDescription md =
 395                                         modules.computeIfAbsent(nameAttr,
 396                                                 n -> new ModuleDescription());
 397                                 removeVersion(md.header, h -> true,
 398                                               platform.version);
 399                                 reader.moveNext();
 400                                 break;
 401                             }
 402                         }
 403                     }
 404                 }
 405             }
 406         }
 407 
 408         ClassList result = new ClassList();
 409 
 410         classes.values().forEach(result::add);
 411         return new LoadDescriptions(result,
 412                                     modules,
 413                                     new ArrayList<>(platforms.values()));
 414     }
 415 
 416     private static void removeVersion(LoadDescriptions load, String deletePlatform) {
 417         for (Iterator<ClassDescription> it = load.classes.iterator(); it.hasNext();) {
 418             ClassDescription desc = it.next();
 419             Iterator<ClassHeaderDescription> chdIt = desc.header.iterator();
 420 
 421             while (chdIt.hasNext()) {
 422                 ClassHeaderDescription chd = chdIt.next();
 423 
 424                 chd.versions = removeVersion(chd.versions, deletePlatform);
 425                 if (chd.versions.isEmpty()) {
 426                     chdIt.remove();
 427                 }
 428             }
 429 
 430             if (desc.header.isEmpty()) {
 431                 it.remove();
 432                 continue;
 433             }
 434 
 435             Iterator<MethodDescription> methodIt = desc.methods.iterator();
 436 
 437             while (methodIt.hasNext()) {
 438                 MethodDescription method = methodIt.next();
 439 
 440                 method.versions = removeVersion(method.versions, deletePlatform);
 441                 if (method.versions.isEmpty())
 442                     methodIt.remove();
 443             }
 444 
 445             Iterator<FieldDescription> fieldIt = desc.fields.iterator();
 446 
 447             while (fieldIt.hasNext()) {
 448                 FieldDescription field = fieldIt.next();
 449 
 450                 field.versions = removeVersion(field.versions, deletePlatform);
 451                 if (field.versions.isEmpty())
 452                     fieldIt.remove();
 453             }


 454         }
 455 
 456         for (Iterator<ModuleDescription> it = load.modules.values().iterator(); it.hasNext();) {
 457             ModuleDescription desc = it.next();

 458             Iterator<ModuleHeaderDescription> mhdIt = desc.header.iterator();
 459 
 460             while (mhdIt.hasNext()) {
 461                 ModuleHeaderDescription mhd = mhdIt.next();
 462 
 463                 mhd.versions = removeVersion(mhd.versions, deletePlatform);
 464                 if (mhd.versions.isEmpty())
 465                     mhdIt.remove();
 466             }
 467 
 468             if (desc.header.isEmpty()) {
 469                 it.remove();
 470                 continue;
 471             }


 472         }




 473     }
 474 
 475     static final class LoadDescriptions {
 476         public final ClassList classes;
 477         public final Map<String, ModuleDescription> modules;
 478         public final List<PlatformInput> versions;
 479 
 480         public LoadDescriptions(ClassList classes,
 481                                 Map<String, ModuleDescription>  modules,
 482                                 List<PlatformInput> versions) {
 483             this.classes = classes;
 484             this.modules = modules;
 485             this.versions = versions;
 486         }
 487 
 488     }
 489 
 490     static final class LineBasedReader implements AutoCloseable {
 491         private final BufferedReader input;
 492         public String lineKey;


 534         Set<String> otherSet = new HashSet<>();
 535 
 536         for (char v : other.toCharArray()) {
 537             otherSet.add("" + v);
 538         }
 539 
 540         return reduce(original, otherSet);
 541     }
 542 
 543     private static String reduce(String original, Set<String> generate) {
 544         StringBuilder sb = new StringBuilder();
 545 
 546         for (char v : original.toCharArray()) {
 547             if (generate.contains("" + v)) {
 548                 sb.append(v);
 549             }
 550         }
 551         return sb.toString();
 552     }
 553 
 554     private static String removeVersion(String original, String remove) {
 555         StringBuilder sb = new StringBuilder();
 556 
 557         for (char v : original.toCharArray()) {
 558             if (v != remove.charAt(0)) {
 559                 sb.append(v);
 560             }
 561         }
 562         return sb.toString();
 563     }
 564 
 565     private static class PlatformInput {
 566         public final String version;
 567         public final String basePlatform;
 568         public final List<String> files;
 569         public final Path ctDescription;
 570         public PlatformInput(Path ctDescription, String version, String basePlatform, List<String> files) {
 571             this.ctDescription = ctDescription;
 572             this.version = version;
 573             this.basePlatform = basePlatform;
 574             this.files = files;
 575         }
 576 
 577         public static PlatformInput load(Path ctDescription, LineBasedReader in) throws IOException {
 578             return new PlatformInput(ctDescription,
 579                                      in.attributes.get("version"),
 580                                      in.attributes.get("base"),
 581                                      List.of(in.attributes.get("files").split(":")));
 582         }
 583     }
 584 


1253                     return i;
1254                 }
1255             }
1256             i++;
1257         }
1258 
1259         return addToCP(constantPool, new CONSTANT_Class_info(null, classNameIndex));
1260     }
1261     //</editor-fold>
1262     //</editor-fold>
1263 
1264     //<editor-fold defaultstate="collapsed" desc="Create Symbol Description">
1265     public void createBaseLine(List<VersionDescription> versions,
1266                                ExcludeIncludeList excludesIncludes,
1267                                Path descDest,
1268                                String[] args) throws IOException {
1269         ClassList classes = new ClassList();
1270         Map<String, ModuleDescription> modules = new HashMap<>();
1271 
1272         for (VersionDescription desc : versions) {
1273             Iterable<byte[]> classFileData = loadClassData(desc.classes);















1274 
1275             loadVersionClasses(classes, modules, classFileData, excludesIncludes, desc.version, null);
1276         }
1277 
1278         List<PlatformInput> platforms =
1279                 versions.stream()
1280                         .map(desc -> new PlatformInput(null,
1281                                                        desc.version,
1282                                                        desc.primaryBaseline,
1283                                                        null))
1284                         .collect(Collectors.toList());
1285 
1286         dumpDescriptions(classes, modules, platforms, Set.of(), descDest.resolve("symbols"), args);
1287     }
1288     //where:
1289         private static final String DO_NO_MODIFY =
1290             "#\n" +
1291             "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" +
1292             "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" +
1293             "#\n" +
1294             "# This code is free software; you can redistribute it and/or modify it\n" +
1295             "# under the terms of the GNU General Public License version 2 only, as\n" +
1296             "# published by the Free Software Foundation.  Oracle designates this\n" +
1297             "# particular file as subject to the \"Classpath\" exception as provided\n" +
1298             "# by Oracle in the LICENSE file that accompanied this code.\n" +
1299             "#\n" +
1300             "# This code is distributed in the hope that it will be useful, but WITHOUT\n" +
1301             "# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +
1302             "# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n" +
1303             "# version 2 for more details (a copy is included in the LICENSE file that\n" +
1304             "# accompanied this code).\n" +
1305             "#\n" +
1306             "# You should have received a copy of the GNU General Public License version\n" +
1307             "# 2 along with this work; if not, write to the Free Software Foundation,\n" +
1308             "# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n" +
1309             "#\n" +
1310             "# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n" +
1311             "# or visit www.oracle.com if you need additional information or have any\n" +
1312             "# questions.\n" +
1313             "#\n" +
1314             "# ##########################################################\n" +
1315             "# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ###\n" +
1316             "# ##########################################################\n" +
1317             "#\n";
1318 
1319         private Iterable<byte[]> loadClassData(String path) {
1320             List<byte[]> classFileData = new ArrayList<>();
1321 
1322             try (BufferedReader descIn =
1323                     Files.newBufferedReader(Paths.get(path))) {
1324                 String line;
1325                 while ((line = descIn.readLine()) != null) {
1326                     ByteArrayOutputStream data = new ByteArrayOutputStream();
1327                     for (int i = 0; i < line.length(); i += 2) {
1328                         String hex = line.substring(i, i + 2);
1329                         data.write(Integer.parseInt(hex, 16));
1330                     }
1331                     classFileData.add(data.toByteArray());
1332                 }
1333             } catch (IOException ex) {
1334                 throw new IllegalStateException(ex);
1335             }
1336 
1337             return classFileData;
1338         }
1339 
1340     private void loadVersionClasses(ClassList classes,
1341                                     Map<String, ModuleDescription> modules,
1342                                     Iterable<byte[]> classData,
1343                                     ExcludeIncludeList excludesIncludes,
1344                                     String version,
1345                                     String baseline) {
1346         Map<String, ModuleDescription> currentVersionModules =
1347                 new HashMap<>();
1348 
1349         for (byte[] classFileData : classData) {
1350             try (InputStream in = new ByteArrayInputStream(classFileData)) {
1351                 inspectModuleInfoClassFile(in,
1352                                            currentVersionModules, version);
1353             } catch (IOException | ConstantPoolException ex) {
1354                 throw new IllegalStateException(ex);
1355             }
1356         }
1357 
1358         ExcludeIncludeList currentEIList = excludesIncludes;
1359 
1360         if (!currentVersionModules.isEmpty()) {
1361             Set<String> includes = new HashSet<>();
1362 
1363             for (ModuleDescription md : currentVersionModules.values()) {
1364                 md.header.get(0).exports.stream().map(e -> e + '/')
1365                                         .forEach(includes::add);


1449                 while(nestMemberIt.hasNext()) {
1450                     String member = nestMemberIt.next();
1451                     if (!includedClasses.contains(member))
1452                         nestMemberIt.remove();
1453                 }
1454             }
1455 
1456             if (header.innerClasses != null) {
1457                 Iterator<InnerClassInfo> innerClassIt = header.innerClasses.iterator();
1458 
1459                 while(innerClassIt.hasNext()) {
1460                     InnerClassInfo ici = innerClassIt.next();
1461                     if (!includedClasses.contains(ici.innerClass))
1462                         innerClassIt.remove();
1463                 }
1464             }
1465 
1466             ClassDescription existing = classes.find(clazz.name, true);
1467 
1468             if (existing != null) {
1469                 addClassHeader(existing, header, version, baseline);
1470                 for (MethodDescription currentMethod : clazz.methods) {
1471                     addMethod(existing, currentMethod, version, baseline);
1472                 }
1473                 for (FieldDescription currentField : clazz.fields) {
1474                     addField(existing, currentField, version, baseline);
1475                 }
1476             } else {
1477                 classes.add(clazz);
1478             }
1479         }
1480 
1481         for (ModuleDescription module : currentVersionModules.values()) {
1482             ModuleHeaderDescription header = module.header.get(0);
1483 
1484             if (header.innerClasses != null) {
1485                 Iterator<InnerClassInfo> innerClassIt =
1486                         header.innerClasses.iterator();
1487 
1488                 while(innerClassIt.hasNext()) {
1489                     InnerClassInfo ici = innerClassIt.next();
1490                     if (!includedClasses.contains(ici.innerClass))
1491                         innerClassIt.remove();
1492                 }
1493             }
1494 
1495             ModuleDescription existing = modules.get(module.name);
1496 
1497             if (existing != null) {
1498                 addModuleHeader(existing, header, version);
1499             } else {
1500                 modules.put(module.name, module);
1501             }
1502         }
1503     }
1504     //where:
1505         private static final String PROPERITARY_ANNOTATION =
1506                 "Lsun/Proprietary+Annotation;";
1507 
1508     private void dumpDescriptions(ClassList classes,
1509                                   Map<String, ModuleDescription> modules,
1510                                   List<PlatformInput> versions,
1511                                   Set<String> forceWriteVersions,
1512                                   Path ctDescriptionFile,
1513                                   String[] args) throws IOException {
1514         classes.sort();
1515 
1516         Map<String, String> package2Modules = new HashMap<>();
1517 
1518         versions.stream()
1519                 .filter(v -> "9".compareTo(v.version) <= 0)
1520                 .sorted((v1, v2) -> v1.version.compareTo(v2.version))
1521                 .forEach(v -> {
1522             for (ModuleDescription md : modules.values()) {
1523                 md.header
1524                   .stream()
1525                   .filter(h -> h.versions.contains(v.version))
1526                   .flatMap(h -> h.exports.stream())
1527                   .map(p -> p.replace('/', '.'))
1528                   .forEach(p -> package2Modules.putIfAbsent(p, md.name));
1529             }
1530         });
1531 


1558             module2Classes.computeIfAbsent(module, m -> new ArrayList<>())
1559                     .add(clazz);
1560         }
1561 
1562         modules.keySet()
1563                .stream()
1564                .filter(m -> !module2Classes.containsKey(m))
1565                .forEach(m -> module2Classes.put(m, Collections.emptyList()));
1566 
1567         Files.createDirectories(ctDescriptionFile.getParent());
1568 
1569         int year = Calendar.getInstance(TimeZone.getTimeZone("UTF"), Locale.ROOT)
1570                            .get(Calendar.YEAR);
1571 
1572         try (Writer symbolsOut = Files.newBufferedWriter(ctDescriptionFile)) {
1573             Map<PlatformInput, List<String>> outputFiles = new LinkedHashMap<>();
1574 
1575             for (PlatformInput desc : versions) {
1576                 List<String> files = desc.files;
1577 
1578                 if (files == null || forceWriteVersions.contains(desc.version)) {
1579                     files = new ArrayList<>();
1580                     for (Entry<String, List<ClassDescription>> e : module2Classes.entrySet()) {
1581                         StringWriter data = new StringWriter();
1582                         ModuleDescription module = modules.get(e.getKey());
1583 
1584                         module.write(data, desc.basePlatform, desc.version);
1585 
1586                         for (ClassDescription clazz : e.getValue()) {
1587                             clazz.write(data, desc.basePlatform, desc.version);
1588                         }
1589 
1590                         String fileName = e.getKey() + "-" + desc.version + ".sym.txt";
1591                         Path f = ctDescriptionFile.getParent().resolve(fileName);
1592 
1593                         String dataString = data.toString();
1594 
1595                         if (!dataString.isEmpty()) {
1596                             String existingYear = null;
1597                             boolean hasChange = true;
1598                             if (Files.isReadable(f)) {
1599                                 String oldContent = Files.readString(f, StandardCharsets.UTF_8);
1600                                 int yearPos = DO_NO_MODIFY.indexOf("{YEAR}");
1601                                 String headerPattern =
1602                                         Pattern.quote(DO_NO_MODIFY.substring(0, yearPos)) +
1603                                         "([0-9]+)(, [0-9]+)?" +
1604                                         Pattern.quote(DO_NO_MODIFY.substring(yearPos + "{YEAR}".length()));
1605                                 String pattern = headerPattern +
1606                                                  Pattern.quote(dataString);
1607                                 Matcher m = Pattern.compile(pattern, Pattern.MULTILINE).matcher(oldContent);
1608                                 if (m.matches()) {
1609                                     hasChange = false;
1610                                 } else {
1611                                     m = Pattern.compile(headerPattern).matcher(oldContent);
1612                                     if (m.find()) {
1613                                         existingYear = m.group(1);
1614                                     }
1615                                 }
1616                             }
1617                             if (hasChange) {
1618                                 try (Writer out = Files.newBufferedWriter(f, StandardCharsets.UTF_8)) {
1619                                     String yearSpec = (existingYear != null ? existingYear + ", " : "") + String.valueOf(year);
1620                                     out.append(DO_NO_MODIFY.replace("{YEAR}", yearSpec));
1621                                     out.write(dataString);
1622                                 }
1623                             }
1624                             files.add(f.getFileName().toString());
1625                         }
1626                     }
1627                 }
1628 
1629                 outputFiles.put(desc, files);
1630             }
1631             symbolsOut.append(DO_NO_MODIFY.replace("{YEAR}", "2015, " + year));
1632             symbolsOut.append("#command used to generate this file:\n");
1633             symbolsOut.append("#")
1634                       .append(CreateSymbols.class.getName())
1635                       .append(" ")
1636                       .append(Arrays.stream(args)
1637                                     .collect(Collectors.joining(" ")))
1638                       .append("\n");
1639             symbolsOut.append("#\n");
1640             symbolsOut.append("generate platforms ")
1641                       .append(versions.stream()
1642                                       .map(v -> v.version)
1643                                       .sorted()
1644                                       .collect(Collectors.joining(":")))
1645                       .append("\n");
1646             for (Entry<PlatformInput, List<String>> versionFileEntry : outputFiles.entrySet()) {
1647                 symbolsOut.append("platform version ")
1648                           .append(versionFileEntry.getKey().version);
1649                 if (versionFileEntry.getKey().basePlatform != null) {
1650                     symbolsOut.append(" base ")
1651                               .append(versionFileEntry.getKey().basePlatform);
1652                 }
1653                 symbolsOut.append(" files ")
1654                           .append(versionFileEntry.getValue()
1655                                                   .stream()
1656                                                   .map(p -> p)
1657                                                   .sorted()
1658                                                   .collect(Collectors.joining(":")))
1659                           .append("\n");
1660             }
1661         }
1662     }
1663 
1664     private void incrementalUpdate(String ctDescriptionFile,
1665                                    String excludeFile,
1666                                    String platformVersion,
1667                                    Iterable<byte[]> classBytes,
1668                                    Function<LoadDescriptions, String> baseline,
1669                                    String[] args) throws IOException {

1670         String currentVersion =
1671                 Integer.toString(Integer.parseInt(platformVersion), Character.MAX_RADIX);
1672         String version = currentVersion.toUpperCase(Locale.ROOT);
1673         Path ctDescriptionPath = Paths.get(ctDescriptionFile).toAbsolutePath();
1674         LoadDescriptions data = load(null, ctDescriptionPath);
1675 
1676         ClassList classes = data.classes;
1677         Map<String, ModuleDescription> modules = data.modules;
1678         List<PlatformInput> versions = data.versions;
1679 
1680         ExcludeIncludeList excludeList =
1681                 ExcludeIncludeList.create(excludeFile);
1682 
1683         loadVersionClasses(classes, modules, classBytes, excludeList, "$", version);
1684 
1685         removeVersion(data, version);
1686 
1687         for (ModuleDescription md : data.modules.values()) {
1688             for (ModuleHeaderDescription header : md.header) {
1689                 header.versions = header.versions.replace("$", version);
1690             }
1691         }
1692 
1693         for (ClassDescription clazzDesc : data.classes) {
1694             for (ClassHeaderDescription header : clazzDesc.header) {
1695                 header.versions = header.versions.replace("$", version);
1696             }
1697             for (MethodDescription method : clazzDesc.methods) {
1698                 method.versions = method.versions.replace("$", version);
1699             }
1700             for (FieldDescription field : clazzDesc.fields) {
1701                 field.versions = field.versions.replace("$", version);
1702             }
1703         }
1704 
1705         if (versions.stream().noneMatch(inp -> version.equals(inp.version))) {
1706             versions.add(new PlatformInput(null, version, baseline.apply(data), null));
1707         }
1708 
1709         Set<String> writeVersions = new HashSet<>();
1710 
1711         writeVersions.add(version);
1712 
1713         //re-write all platforms that have version as their basline:
1714         versions.stream()
1715                 .filter(inp -> version.equals(inp.basePlatform))
1716                 .map(inp -> inp.version)
1717                 .forEach(writeVersions::add);
1718         dumpDescriptions(classes, modules, versions, writeVersions, ctDescriptionPath, args);
1719     }
1720 
1721     public void createIncrementalBaseLineFromDataFile(String ctDescriptionFile,
1722                                                       String excludeFile,
1723                                                       String version,
1724                                                       String dataFile,
1725                                                       String baseline,
1726                                                       String[] args) throws IOException {
1727         incrementalUpdate(ctDescriptionFile, excludeFile, version, loadClassData(dataFile), x -> baseline, args);
1728     }
1729 
1730     public void createIncrementalBaseLine(String ctDescriptionFile,
1731                                           String excludeFile,
1732                                           String[] args) throws IOException {
1733         String specVersion = System.getProperty("java.specification.version");
1734         Iterable<byte[]> classBytes = dumpCurrentClasses();
1735         Function<LoadDescriptions, String> baseline = data -> {
1736             if (data.versions.isEmpty()) {
1737                 return null;
1738             } else {
1739                 return data.versions.stream()
1740                                     .sorted((v1, v2) -> v2.version.compareTo(v1.version))
1741                                     .findFirst()
1742                                     .get()
1743                                     .version;
1744             }
1745         };
1746         incrementalUpdate(ctDescriptionFile, excludeFile, specVersion, classBytes, baseline, args);

1747     }
1748 
1749     private List<byte[]> dumpCurrentClasses() throws IOException {
1750         JavacTool tool = JavacTool.create();
1751         Context ctx = new Context();
1752         String version = System.getProperty("java.specification.version");
1753         JavacTask task = tool.getTask(null, null, null,
1754                                       List.of("--release", version),
1755                                       null, null, ctx);
1756         task.getElements().getTypeElement("java.lang.Object");
1757         JavaFileManager fm = ctx.get(JavaFileManager.class);
1758 
1759         List<byte[]> data = new ArrayList<>();
1760         for (Location modLoc : LOCATIONS) {
1761             for (Set<JavaFileManager.Location> module :
1762                     fm.listLocationsForModules(modLoc)) {
1763                 for (JavaFileManager.Location loc : module) {
1764                     Iterable<JavaFileObject> files =
1765                             fm.list(loc,
1766                                     "",


1820         for (Attribute attr : cf.attributes) {
1821             if (!readAttribute(cf, headerDesc, attr))
1822                 return ;
1823         }
1824 
1825         ClassDescription clazzDesc = null;
1826 
1827         for (ClassDescription cd : classes) {
1828             if (cd.name.equals(cf.getName())) {
1829                 clazzDesc = cd;
1830                 break;
1831             }
1832         }
1833 
1834         if (clazzDesc == null) {
1835             clazzDesc = new ClassDescription();
1836             clazzDesc.name = cf.getName();
1837             classes.add(clazzDesc);
1838         }
1839 
1840         addClassHeader(clazzDesc, headerDesc, version, null);
1841 
1842         for (Method m : cf.methods) {
1843             if (!include(m.access_flags.flags))
1844                 continue;
1845             MethodDescription methDesc = new MethodDescription();
1846             methDesc.flags = m.access_flags.flags;
1847             methDesc.name = m.getName(cf.constant_pool);
1848             methDesc.descriptor = m.descriptor.getValue(cf.constant_pool);
1849             for (Attribute attr : m.attributes) {
1850                 readAttribute(cf, methDesc, attr);
1851             }
1852             addMethod(clazzDesc, methDesc, version, null);
1853         }
1854         for (Field f : cf.fields) {
1855             if (!include(f.access_flags.flags))
1856                 continue;
1857             FieldDescription fieldDesc = new FieldDescription();
1858             fieldDesc.flags = f.access_flags.flags;
1859             fieldDesc.name = f.getName(cf.constant_pool);
1860             fieldDesc.descriptor = f.descriptor.getValue(cf.constant_pool);
1861             for (Attribute attr : f.attributes) {
1862                 readAttribute(cf, fieldDesc, attr);
1863             }
1864             addField(clazzDesc, fieldDesc, version, null);
1865         }
1866     }
1867 
1868     private void inspectModuleInfoClassFile(InputStream in,
1869             Map<String, ModuleDescription> modules,
1870             String version) throws IOException, ConstantPoolException {
1871         ClassFile cf = ClassFile.read(in);
1872 
1873         if (!cf.access_flags.is(AccessFlags.ACC_MODULE)) {
1874             return ;
1875         }
1876 
1877         ModuleHeaderDescription headerDesc = new ModuleHeaderDescription();
1878 
1879         headerDesc.versions = version;
1880         headerDesc.flags = cf.access_flags.flags;
1881 
1882         for (Attribute attr : cf.attributes) {
1883             if (!readAttribute(cf, headerDesc, attr))
1884                 return ;


1903         //normalize:
1904         boolean existed = false;
1905         for (ModuleHeaderDescription existing : moduleDesc.header) {
1906             if (existing.equals(headerDesc)) {
1907                 headerDesc = existing;
1908                 existed = true;
1909             }
1910         }
1911 
1912         headerDesc.versions += version;
1913 
1914         if (!existed) {
1915             moduleDesc.header.add(headerDesc);
1916         }
1917     }
1918 
1919     private boolean include(int accessFlags) {
1920         return (accessFlags & (AccessFlags.ACC_PUBLIC | AccessFlags.ACC_PROTECTED)) != 0;
1921     }
1922 
1923     private void addClassHeader(ClassDescription clazzDesc, ClassHeaderDescription headerDesc, String version, String baseline) {
1924         //normalize:
1925         boolean existed = false;
1926         for (ClassHeaderDescription existing : clazzDesc.header) {
1927             if (existing.equals(headerDesc) && (!existed || (baseline != null && existing.versions.contains(baseline)))) {
1928                 headerDesc = existing;
1929                 existed = true;
1930             }
1931         }
1932 
1933         if (!existed) {
1934             //check if the only difference between the 7 and 8 version is the Profile annotation
1935             //if so, copy it to the pre-8 version, so save space
1936             for (ClassHeaderDescription existing : clazzDesc.header) {
1937                 List<AnnotationDescription> annots = existing.classAnnotations;
1938 
1939                 if (annots != null) {
1940                     for (AnnotationDescription ad : annots) {
1941                         if (PROFILE_ANNOTATION.equals(ad.annotationType)) {
1942                             existing.classAnnotations = new ArrayList<>(annots);
1943                             existing.classAnnotations.remove(ad);
1944                             if (existing.equals(headerDesc)) {
1945                                 headerDesc = existing;
1946                                 existed = true;
1947                             }
1948                             existing.classAnnotations = annots;
1949                             break;
1950                         }
1951                     }
1952                 }
1953             }
1954         }
1955 
1956         headerDesc.versions += version;
1957 
1958         if (!existed) {
1959             clazzDesc.header.add(headerDesc);
1960         }
1961     }
1962 
1963     private void addMethod(ClassDescription clazzDesc, MethodDescription methDesc, String version, String baseline) {
1964         //normalize:
1965         boolean methodExisted = false;
1966         for (MethodDescription existing : clazzDesc.methods) {
1967             if (existing.equals(methDesc) && (!methodExisted || (baseline != null && existing.versions.contains(baseline)))) {
1968                 methodExisted = true;
1969                 methDesc = existing;

1970             }
1971         }
1972         methDesc.versions += version;
1973         if (!methodExisted) {
1974             clazzDesc.methods.add(methDesc);
1975         }
1976     }
1977 
1978     private void addField(ClassDescription clazzDesc, FieldDescription fieldDesc, String version, String baseline) {
1979         boolean fieldExisted = false;
1980         for (FieldDescription existing : clazzDesc.fields) {
1981             if (existing.equals(fieldDesc) && (!fieldExisted || (baseline != null && existing.versions.contains(baseline)))) {
1982                 fieldExisted = true;
1983                 fieldDesc = existing;

1984             }
1985         }
1986         fieldDesc.versions += version;
1987         if (!fieldExisted) {
1988             clazzDesc.fields.add(fieldDesc);
1989         }
1990     }
1991 
1992     private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribute attr) throws ConstantPoolException {
1993         String attrName = attr.getName(cf.constant_pool);
1994         switch (attrName) {
1995             case Attribute.AnnotationDefault:
1996                 assert feature instanceof MethodDescription;
1997                 element_value defaultValue = ((AnnotationDefault_attribute) attr).default_value;
1998                 ((MethodDescription) feature).annotationDefaultValue =
1999                         convertElementValue(cf.constant_pool, defaultValue);
2000                 break;
2001             case "Deprecated":
2002                 feature.deprecated = true;
2003                 break;


2372         }
2373 
2374         private static boolean matches(Set<String> list, String className) {
2375             if (list.contains(className))
2376                 return true;
2377             String pack = className.substring(0, className.lastIndexOf('/') + 1);
2378             return list.contains(pack);
2379         }
2380     }
2381     //</editor-fold>
2382 
2383     //<editor-fold defaultstate="collapsed" desc="Class Data Structures">
2384     static boolean checkChange(String versions, String version,
2385                                String baselineVersion) {
2386         return versions.contains(version) ^
2387                (baselineVersion != null &&
2388                 versions.contains(baselineVersion));
2389     }
2390 
2391     static abstract class FeatureDescription {
2392         int flagsNormalization = ~0;
2393         int flags;
2394         boolean deprecated;
2395         String signature;
2396         String versions = "";
2397         List<AnnotationDescription> classAnnotations;
2398         List<AnnotationDescription> runtimeAnnotations;
2399 
2400         protected void writeAttributes(Appendable output) throws IOException {
2401             if (flags != 0)
2402                 output.append(" flags " + Integer.toHexString(flags));
2403             if (deprecated) {
2404                 output.append(" deprecated true");
2405             }
2406             if (signature != null) {
2407                 output.append(" signature " + quote(signature, false));
2408             }
2409             if (classAnnotations != null && !classAnnotations.isEmpty()) {
2410                 output.append(" classAnnotations ");
2411                 for (AnnotationDescription a : classAnnotations) {
2412                     output.append(quote(a.toString(), false));


2437             String inDeprecated = reader.attributes.get("deprecated");
2438             if ("true".equals(inDeprecated)) {
2439                 deprecated = true;
2440             }
2441             signature = reader.attributes.get("signature");
2442             String inClassAnnotations = reader.attributes.get("classAnnotations");
2443             if (inClassAnnotations != null) {
2444                 classAnnotations = parseAnnotations(inClassAnnotations, new int[1]);
2445             }
2446             String inRuntimeAnnotations = reader.attributes.get("runtimeAnnotations");
2447             if (inRuntimeAnnotations != null) {
2448                 runtimeAnnotations = parseAnnotations(inRuntimeAnnotations, new int[1]);
2449             }
2450         }
2451 
2452         public abstract boolean read(LineBasedReader reader) throws IOException;
2453 
2454         @Override
2455         public int hashCode() {
2456             int hash = 3;
2457             hash = 89 * hash + (this.flags & flagsNormalization);
2458             hash = 89 * hash + (this.deprecated ? 1 : 0);
2459             hash = 89 * hash + Objects.hashCode(this.signature);
2460             hash = 89 * hash + listHashCode(this.classAnnotations);
2461             hash = 89 * hash + listHashCode(this.runtimeAnnotations);
2462             return hash;
2463         }
2464 
2465         @Override
2466         public boolean equals(Object obj) {
2467             if (obj == null) {
2468                 return false;
2469             }
2470             if (getClass() != obj.getClass()) {
2471                 return false;
2472             }
2473             final FeatureDescription other = (FeatureDescription) obj;
2474             if ((this.flags & flagsNormalization) != (other.flags & flagsNormalization)) {
2475                 return false;
2476             }
2477             if (this.deprecated != other.deprecated) {
2478                 return false;
2479             }
2480             if (!Objects.equals(this.signature, other.signature)) {
2481                 return false;
2482             }
2483             if (!listEquals(this.classAnnotations, other.classAnnotations)) {
2484                 return false;
2485             }
2486             if (!listEquals(this.runtimeAnnotations, other.runtimeAnnotations)) {
2487                 return false;
2488             }
2489             return true;
2490         }
2491 
2492     }
2493 
2494     public static class ModuleDescription {


3106             while ("innerclass".equals(reader.lineKey)) {
3107                 InnerClassInfo info = new InnerClassInfo();
3108 
3109                 info.innerClass = reader.attributes.get("innerClass");
3110                 info.outerClass = reader.attributes.get("outerClass");
3111                 info.innerClassName = reader.attributes.get("innerClassName");
3112 
3113                 String inFlags = reader.attributes.get("flags");
3114                 if (inFlags != null && !inFlags.isEmpty())
3115                     info.innerClassFlags = Integer.parseInt(inFlags, 16);
3116 
3117                 innerClasses.add(info);
3118 
3119                 reader.moveNext();
3120             }
3121         }
3122 
3123     }
3124 
3125     static class MethodDescription extends FeatureDescription {
3126         static int METHODS_FLAGS_NORMALIZATION = ~0;
3127         String name;
3128         String descriptor;
3129         List<String> thrownTypes;
3130         Object annotationDefaultValue;
3131         List<List<AnnotationDescription>> classParameterAnnotations;
3132         List<List<AnnotationDescription>> runtimeParameterAnnotations;
3133 
3134         public MethodDescription() {
3135             flagsNormalization = METHODS_FLAGS_NORMALIZATION;
3136         }
3137 
3138         @Override
3139         public int hashCode() {
3140             int hash = super.hashCode();
3141             hash = 59 * hash + Objects.hashCode(this.name);
3142             hash = 59 * hash + Objects.hashCode(this.descriptor);
3143             hash = 59 * hash + Objects.hashCode(this.thrownTypes);
3144             hash = 59 * hash + Objects.hashCode(this.annotationDefaultValue);
3145             return hash;
3146         }
3147 
3148         @Override
3149         public boolean equals(Object obj) {
3150             if (obj == null) {
3151                 return false;
3152             }
3153             if (!super.equals(obj)) {
3154                 return false;
3155             }
3156             final MethodDescription other = (MethodDescription) obj;
3157             if (!Objects.equals(this.name, other.name)) {


3840                         Files.delete(file);
3841                         return FileVisitResult.CONTINUE;
3842                     }
3843                     @Override
3844                     public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
3845                         return FileVisitResult.CONTINUE;
3846                     }
3847                     @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
3848                         Files.delete(dir);
3849                         return FileVisitResult.CONTINUE;
3850                     }
3851                 });
3852 
3853                 ExcludeIncludeList excludeList =
3854                         ExcludeIncludeList.create(args[2]);
3855 
3856                 new CreateSymbols().createBaseLine(versions,
3857                                                    excludeList,
3858                                                    descDest,
3859                                                    args);
3860                 break;
3861             }
3862             case "build-description-incremental-file": {
3863                 if (args.length != 6 && args.length != 7) {
3864                     help();
3865                     return ;
3866                 }
3867 
3868                 if (args.length == 7) {
3869                     if ("--normalize-method-flags".equals(args[6])) {
3870                         MethodDescription.METHODS_FLAGS_NORMALIZATION = ~(0x100 | 0x20);
3871                     } else {
3872                         help();
3873                         return ;
3874                     }
3875                 }
3876 
3877                 new CreateSymbols().createIncrementalBaseLineFromDataFile(args[1], args[2], args[3], args[4], "<none>".equals(args[5]) ? null : args[5], args);
3878                 break;
3879             }
3880             case "build-description-incremental": {
3881                 if (args.length != 3) {
3882                     help();
3883                     return ;
3884                 }
3885 
3886                 new CreateSymbols().createIncrementalBaseLine(args[1], args[2], args);
3887                 break;
3888             }
3889             case "build-ctsym":
3890                 String ctDescriptionFileExtra;
3891                 String ctDescriptionFile;
3892                 String ctSymLocation;
3893                 String timestampSpec;
3894                 String currentVersion;
3895                 String systemModules;
3896 
3897                 if (args.length == 6) {


< prev index next >