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) {
|