103 import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info;
104 import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
105 import com.sun.tools.classfile.ConstantPool.CPInfo;
106 import com.sun.tools.classfile.ConstantPool.InvalidIndex;
107 import com.sun.tools.classfile.ConstantPoolException;
108 import com.sun.tools.classfile.ConstantValue_attribute;
109 import com.sun.tools.classfile.Deprecated_attribute;
110 import com.sun.tools.classfile.Descriptor;
111 import com.sun.tools.classfile.Exceptions_attribute;
112 import com.sun.tools.classfile.Field;
113 import com.sun.tools.classfile.InnerClasses_attribute;
114 import com.sun.tools.classfile.InnerClasses_attribute.Info;
115 import com.sun.tools.classfile.Method;
116 import com.sun.tools.classfile.ModuleResolution_attribute;
117 import com.sun.tools.classfile.ModuleTarget_attribute;
118 import com.sun.tools.classfile.Module_attribute;
119 import com.sun.tools.classfile.Module_attribute.ExportsEntry;
120 import com.sun.tools.classfile.Module_attribute.OpensEntry;
121 import com.sun.tools.classfile.Module_attribute.ProvidesEntry;
122 import com.sun.tools.classfile.Module_attribute.RequiresEntry;
123 import com.sun.tools.classfile.RuntimeAnnotations_attribute;
124 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
125 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
126 import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute;
127 import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
128 import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
129 import com.sun.tools.classfile.Signature_attribute;
130 import com.sun.tools.javac.api.JavacTool;
131 import com.sun.tools.javac.jvm.Target;
132 import com.sun.tools.javac.util.Assert;
133 import com.sun.tools.javac.util.Context;
134 import com.sun.tools.javac.util.Pair;
135
136 /**
137 * A tool for processing the .sym.txt files. It allows to:
138 * * convert the .sym.txt into class/sig files for ct.sym
139 * * in cooperation with the adjacent history Probe, construct .sym.txt files for previous platforms
140 * * enhance existing .sym.txt files with a a new set .sym.txt for the current platform
141 *
142 * To convert the .sym.txt files to class/sig files from ct.sym, run:
143 * java build.tool.symbolgenerator.CreateSymbols build-ctsym <platform-description-file> <target-directory>
144 *
145 * The <platform-description-file> is a file of this format:
146 * generate platforms <platform-ids-to-generate separate with ':'>
147 * platform version <platform-id1> files <.sym.txt files containing history data for given platform, separate with ':'>
148 * platform version <platform-id2> base <base-platform-id> files <.sym.txt files containing history data for given platform, separate with ':'>
149 *
150 * The content of platform "<base-platform-id>" is also automatically added to the content of
151 * platform "<platform-id2>", unless explicitly excluded in "<platform-id2>"'s .sym.txt files.
152 *
153 * To create the .sym.txt files, first run the history Probe for all the previous platforms:
154 * <jdk-N>/bin/java build.tools.symbolgenerator.Probe <classes-for-N>
155 *
156 * Where <classes-for-N> is a name of a file into which the classes from the bootclasspath of <jdk-N>
157 * will be written.
169 * Several include list files may be specified, separated by File.pathSeparator.
170 *
171 * When <diff-against-platformN> is specified, the .sym.txt files for platform N will only contain
172 * differences between platform N and the specified platform. The first platform (denoted F further)
173 * that is specified should use literal value "<none>", to have all the APIs of the platform written to
174 * the .sym.txt files. If there is an existing platform with full .sym.txt files in the repository,
175 * that platform should be used as the first platform to avoid unnecessary changes to the .sym.txt
176 * files. The <diff-against-platformN> for platform N should be determined as follows: if N < F, then
177 * <diff-against-platformN> should be N + 1. If F < N, then <diff-against-platformN> should be N - 1.
178 * If N is a custom/specialized sub-version of another platform N', then <diff-against-platformN> should be N'.
179 *
180 * To generate the .sym.txt files for OpenJDK 7 and 8:
181 * <jdk-7>/bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes
182 * <jdk-8>/bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes
183 * java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list
184 * 8 OpenJDK8.classes '<none>'
185 * 7 OpenJDK7.classes 8
186 *
187 * Note: the versions are expected to be a single character.
188 *
189 * To enhance existing historical data with data for JDK N, run:
190 * <jdk-N>/bin/java build.tools.symbolgenerator.CreateSymbols build-description-incremental make/data/symbols/symbols make/data/symbols/include.list
191 *
192 */
193 public class CreateSymbols {
194
195 //<editor-fold defaultstate="collapsed" desc="ct.sym construction">
196 /**Create sig files for ct.sym reading the classes description from the directory that contains
197 * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
198 */
199 @SuppressWarnings("unchecked")
200 public void createSymbols(String ctDescriptionFile, String ctSymLocation, CtSymKind ctSymKind) throws IOException {
201 LoadDescriptions data = load(Paths.get(ctDescriptionFile), null);
202
203 splitHeaders(data.classes);
204
205 for (ModuleDescription md : data.modules.values()) {
206 for (ModuleHeaderDescription mhd : md.header) {
207 List<String> versionsList =
208 Collections.singletonList(mhd.versions);
209 writeModulesForVersions(ctSymLocation,
210 md,
211 mhd,
212 versionsList);
213 }
214 }
215
216 for (ClassDescription classDescription : data.classes) {
217 for (ClassHeaderDescription header : classDescription.header) {
218 switch (ctSymKind) {
219 case JOINED_VERSIONS:
220 Set<String> jointVersions = new HashSet<>();
221 jointVersions.add(header.versions);
222 limitJointVersion(jointVersions, classDescription.fields);
223 limitJointVersion(jointVersions, classDescription.methods);
224 writeClassesForVersions(ctSymLocation, classDescription, header, jointVersions);
225 break;
226 case SEPARATE:
227 Set<String> versions = new HashSet<>();
228 for (char v : header.versions.toCharArray()) {
229 versions.add("" + v);
230 }
231 writeClassesForVersions(ctSymLocation, classDescription, header, versions);
232 break;
233 }
234 }
235 }
236 }
237
238 public static String EXTENSION = ".sig";
239
240 LoadDescriptions load(Path ctDescription, String deletePlatform) throws IOException {
241 List<PlatformInput> platforms = new ArrayList<>();
242 Set<String> generatePlatforms = null;
243
244 try (LineBasedReader reader = new LineBasedReader(ctDescription)) {
245 while (reader.hasNext()) {
246 switch (reader.lineKey) {
247 case "generate":
248 String[] platformsAttr = reader.attributes.get("platforms").split(":");
249 generatePlatforms = new HashSet<>(List.of(platformsAttr));
250 generatePlatforms.remove(deletePlatform);
251 reader.moveNext();
252 break;
253 case "platform":
254 PlatformInput platform = PlatformInput.load(reader);
255 if (!platform.version.equals(deletePlatform))
256 platforms.add(platform);
257 reader.moveNext();
258 break;
259 default:
260 throw new IllegalStateException("Unknown key: " + reader.lineKey);
261 }
262 }
263 }
264
265 Map<String, ClassDescription> classes = new LinkedHashMap<>();
266 Map<String, ModuleDescription> modules = new LinkedHashMap<>();
267
268 for (PlatformInput platform: platforms) {
269 for (ClassDescription cd : classes.values()) {
270 addNewVersion(cd.header, platform.basePlatform, platform.version);
271 addNewVersion(cd.fields, platform.basePlatform, platform.version);
272 addNewVersion(cd.methods, platform.basePlatform, platform.version);
273 }
274 for (ModuleDescription md : modules.values()) {
275 addNewVersion(md.header, platform.basePlatform, platform.version);
276 }
277 for (String input : platform.files) {
278 Path inputFile = ctDescription.getParent().resolve(input);
279 try (LineBasedReader reader = new LineBasedReader(inputFile)) {
280 while (reader.hasNext()) {
281 String nameAttr = reader.attributes.get("name");
282 switch (reader.lineKey) {
283 case "class": case "-class":
284 ClassDescription cd =
285 classes.computeIfAbsent(nameAttr,
286 n -> new ClassDescription());
287 if ("-class".equals(reader.lineKey)) {
288 removeVersion(cd.header, h -> true,
289 platform.version);
290 reader.moveNext();
291 continue;
292 }
293 cd.read(reader, platform.basePlatform,
294 platform.version);
295 break;
296 case "module": {
297 ModuleDescription md =
298 modules.computeIfAbsent(nameAttr,
359 Map<String, ModuleDescription> moduleList = new HashMap<>();
360
361 for (ModuleDescription desc : modules.values()) {
362 Iterator<ModuleHeaderDescription> mhdIt = desc.header.iterator();
363
364 while (mhdIt.hasNext()) {
365 ModuleHeaderDescription mhd = mhdIt.next();
366
367 mhd.versions = reduce(mhd.versions, generatePlatforms);
368 if (mhd.versions.isEmpty())
369 mhdIt.remove();
370 }
371
372 if (desc.header.isEmpty()) {
373 continue;
374 }
375
376 moduleList.put(desc.name, desc);
377 }
378
379 return new LoadDescriptions(result, moduleList, platforms);
380 }
381
382 static final class LoadDescriptions {
383 public final ClassList classes;
384 public final Map<String, ModuleDescription> modules;
385 public final List<PlatformInput> versions;
386
387 public LoadDescriptions(ClassList classes,
388 Map<String, ModuleDescription> modules,
389 List<PlatformInput> versions) {
390 this.classes = classes;
391 this.modules = modules;
392 this.versions = versions;
393 }
394
395 }
396
397 static final class LineBasedReader implements AutoCloseable {
398 private final BufferedReader input;
399 public String lineKey;
445 }
446
447 return reduce(original, otherSet);
448 }
449
450 private static String reduce(String original, Set<String> generate) {
451 StringBuilder sb = new StringBuilder();
452
453 for (char v : original.toCharArray()) {
454 if (generate.contains("" + v)) {
455 sb.append(v);
456 }
457 }
458 return sb.toString();
459 }
460
461 private static class PlatformInput {
462 public final String version;
463 public final String basePlatform;
464 public final List<String> files;
465 public PlatformInput(String version, String basePlatform, List<String> files) {
466 this.version = version;
467 this.basePlatform = basePlatform;
468 this.files = files;
469 }
470
471 public static PlatformInput load(LineBasedReader in) throws IOException {
472 return new PlatformInput(in.attributes.get("version"),
473 in.attributes.get("base"),
474 List.of(in.attributes.get("files").split(":")));
475 }
476 }
477
478 static void addNewVersion(Collection<? extends FeatureDescription> features,
479 String baselineVersion,
480 String version) {
481 features.stream()
482 .filter(f -> f.versions.contains(baselineVersion))
483 .forEach(f -> f.versions += version);
484 }
485
486 static <T extends FeatureDescription> void removeVersion(Collection<T> features,
487 Predicate<T> shouldRemove,
488 String version) {
489 for (T existing : features) {
490 if (shouldRemove.test(existing) && existing.versions.endsWith(version)) {
491 existing.versions = existing.versions.replace(version, "");
492 return;
800 String e) {
801 return new ExportsEntry(addPackageName(cp, e), 0, new int[0]);
802 }
803
804 private static OpensEntry createOpensEntry(List<CPInfo> cp, String e) {
805 return new OpensEntry(addPackageName(cp, e), 0, new int[0]);
806 }
807
808 private static ProvidesEntry createProvidesEntry(List<CPInfo> cp,
809 ModuleHeaderDescription.ProvidesDescription p) {
810 final int idx = addClassName(cp, p.interfaceName);
811 return new ProvidesEntry(idx, p.implNames
812 .stream()
813 .mapToInt(i -> addClassName(cp, i))
814 .toArray());
815 }
816
817 private void addAttributes(ClassHeaderDescription header,
818 List<CPInfo> constantPool, Map<String, Attribute> attributes) {
819 addGenericAttributes(header, constantPool, attributes);
820 addInnerClassesAttribute(header, constantPool, attributes);
821 }
822
823 private void addInnerClassesAttribute(HeaderDescription header,
824 List<CPInfo> constantPool, Map<String, Attribute> attributes) {
825 if (header.innerClasses != null && !header.innerClasses.isEmpty()) {
826 Info[] innerClasses = new Info[header.innerClasses.size()];
827 int i = 0;
828 for (InnerClassInfo info : header.innerClasses) {
829 innerClasses[i++] =
830 new Info(info.innerClass == null ? 0 : addClass(constantPool, info.innerClass),
831 info.outerClass == null ? 0 : addClass(constantPool, info.outerClass),
832 info.innerClassName == null ? 0 : addString(constantPool, info.innerClassName),
833 new AccessFlags(info.innerClassFlags));
834 }
835 int attributeString = addString(constantPool, Attribute.InnerClasses);
836 attributes.put(Attribute.InnerClasses,
837 new InnerClasses_attribute(attributeString, innerClasses));
838 }
839 }
1134 try (BufferedReader descIn =
1135 Files.newBufferedReader(Paths.get(desc.classes))) {
1136 String line;
1137 while ((line = descIn.readLine()) != null) {
1138 ByteArrayOutputStream data = new ByteArrayOutputStream();
1139 for (int i = 0; i < line.length(); i += 2) {
1140 String hex = line.substring(i, i + 2);
1141 data.write(Integer.parseInt(hex, 16));
1142 }
1143 classFileData.add(data.toByteArray());
1144 }
1145 } catch (IOException ex) {
1146 throw new IllegalStateException(ex);
1147 }
1148
1149 loadVersionClasses(classes, modules, classFileData, excludesIncludes, desc.version);
1150 }
1151
1152 List<PlatformInput> platforms =
1153 versions.stream()
1154 .map(desc -> new PlatformInput(desc.version,
1155 desc.primaryBaseline,
1156 null))
1157 .collect(Collectors.toList());
1158
1159 dumpDescriptions(classes, modules, platforms, descDest.resolve("symbols"), args);
1160 }
1161 //where:
1162 private static final String DO_NO_MODIFY =
1163 "#\n" +
1164 "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" +
1165 "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" +
1166 "#\n" +
1167 "# This code is free software; you can redistribute it and/or modify it\n" +
1168 "# under the terms of the GNU General Public License version 2 only, as\n" +
1169 "# published by the Free Software Foundation. Oracle designates this\n" +
1170 "# particular file as subject to the \"Classpath\" exception as provided\n" +
1171 "# by Oracle in the LICENSE file that accompanied this code.\n" +
1172 "#\n" +
1173 "# This code is distributed in the hope that it will be useful, but WITHOUT\n" +
1174 "# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +
1277 currentVersionClasses);
1278 modified |= includeOutputType(clazz.fields,
1279 f -> f.descriptor,
1280 includedClasses,
1281 currentVersionClasses);
1282 modified |= includeOutputType(clazz.methods,
1283 m -> m.descriptor,
1284 includedClasses,
1285 currentVersionClasses);
1286 }
1287 }
1288 } while (modified);
1289
1290 for (ClassDescription clazz : currentVersionClasses) {
1291 if (!includedClasses.contains(clazz.name)) {
1292 continue;
1293 }
1294
1295 ClassHeaderDescription header = clazz.header.get(0);
1296
1297 if (header.innerClasses != null) {
1298 Iterator<InnerClassInfo> innerClassIt = header.innerClasses.iterator();
1299
1300 while(innerClassIt.hasNext()) {
1301 InnerClassInfo ici = innerClassIt.next();
1302 if (!includedClasses.contains(ici.innerClass))
1303 innerClassIt.remove();
1304 }
1305 }
1306
1307 ClassDescription existing = classes.find(clazz.name, true);
1308
1309 if (existing != null) {
1310 addClassHeader(existing, header, version);
1311 for (MethodDescription currentMethod : clazz.methods) {
1312 addMethod(existing, currentMethod, version);
1313 }
1314 for (FieldDescription currentField : clazz.fields) {
1315 addField(existing, currentField, version);
1316 }
1338 if (existing != null) {
1339 addModuleHeader(existing, header, version);
1340 } else {
1341 modules.put(module.name, module);
1342 }
1343 }
1344 }
1345 //where:
1346 private static final String PROPERITARY_ANNOTATION =
1347 "Lsun/Proprietary+Annotation;";
1348
1349 private void dumpDescriptions(ClassList classes,
1350 Map<String, ModuleDescription> modules,
1351 List<PlatformInput> versions,
1352 Path ctDescriptionFile,
1353 String[] args) throws IOException {
1354 classes.sort();
1355
1356 Map<String, String> package2Modules = new HashMap<>();
1357
1358 for (ModuleDescription md : modules.values()) {
1359 md.header
1360 .stream()
1361 .filter(h -> h.versions.contains("9"))
1362 .flatMap(h -> h.exports.stream())
1363 .map(p -> p.replace('/', '.'))
1364 .forEach(p -> package2Modules.put(p, md.name));
1365 }
1366
1367 package2Modules.put("java.awt.dnd.peer", "java.desktop");
1368 package2Modules.put("java.awt.peer", "java.desktop");
1369 package2Modules.put("jdk", "java.base");
1370
1371 Map<String, List<ClassDescription>> module2Classes = new HashMap<>();
1372
1373 for (ClassDescription clazz : classes) {
1374 String pack = clazz.packge();
1375 String module = package2Modules.get(pack);
1376
1377 if (module == null) {
1378 module = "java.base";
1379
1380 OUTER: while (!pack.isEmpty()) {
1381 for (Entry<String, String> p2M : package2Modules.entrySet()) {
1382 if (p2M.getKey().startsWith(pack)) {
1383 module = p2M.getValue();
1384 break OUTER;
1385 }
1463 }
1464 symbolsOut.append(" files ")
1465 .append(versionFileEntry.getValue()
1466 .stream()
1467 .map(p -> p)
1468 .sorted()
1469 .collect(Collectors.joining(":")))
1470 .append("\n");
1471 }
1472 }
1473 }
1474
1475 public void createIncrementalBaseLine(String ctDescriptionFile,
1476 String excludeFile,
1477 String[] args) throws IOException {
1478 String specVersion = System.getProperty("java.specification.version");
1479 String currentVersion =
1480 Integer.toString(Integer.parseInt(specVersion), Character.MAX_RADIX);
1481 currentVersion = currentVersion.toUpperCase(Locale.ROOT);
1482 Path ctDescriptionPath = Paths.get(ctDescriptionFile).toAbsolutePath();
1483 LoadDescriptions data = load(ctDescriptionPath, currentVersion);
1484
1485 ClassList classes = data.classes;
1486 Map<String, ModuleDescription> modules = data.modules;
1487 List<PlatformInput> versions = data.versions;
1488
1489 ExcludeIncludeList excludeList =
1490 ExcludeIncludeList.create(excludeFile);
1491
1492 Iterable<byte[]> classBytes = dumpCurrentClasses();
1493 loadVersionClasses(classes, modules, classBytes, excludeList, currentVersion);
1494
1495 String baseline;
1496
1497 if (versions.isEmpty()) {
1498 baseline = null;
1499 } else {
1500 baseline = versions.stream()
1501 .sorted((v1, v2) -> v2.version.compareTo(v1.version))
1502 .findFirst()
1503 .get()
1504 .version;
1505 }
1506
1507 versions.add(new PlatformInput(currentVersion, baseline, null));
1508 dumpDescriptions(classes, modules, versions, ctDescriptionPath, args);
1509 }
1510
1511 private List<byte[]> dumpCurrentClasses() throws IOException {
1512 JavacTool tool = JavacTool.create();
1513 Context ctx = new Context();
1514 String version = System.getProperty("java.specification.version");
1515 JavacTask task = tool.getTask(null, null, null,
1516 List.of("--release", version),
1517 null, null, ctx);
1518 task.getElements().getTypeElement("java.lang.Object");
1519 JavaFileManager fm = ctx.get(JavaFileManager.class);
1520
1521 List<byte[]> data = new ArrayList<>();
1522 for (Location modLoc : LOCATIONS) {
1523 for (Set<JavaFileManager.Location> module :
1524 fm.listLocationsForModules(modLoc)) {
1525 for (JavaFileManager.Location loc : module) {
1526 Iterable<JavaFileObject> files =
1527 fm.list(loc,
1865 ModuleTarget_attribute mod = (ModuleTarget_attribute) attr;
1866 if (mod.target_platform_index != 0) {
1867 header.moduleTarget =
1868 cf.constant_pool
1869 .getUTF8Value(mod.target_platform_index);
1870 }
1871 break;
1872 }
1873 case Attribute.ModuleResolution: {
1874 assert feature instanceof ModuleHeaderDescription;
1875 ModuleHeaderDescription header =
1876 (ModuleHeaderDescription) feature;
1877 ModuleResolution_attribute mod =
1878 (ModuleResolution_attribute) attr;
1879 header.moduleResolution = mod.resolution_flags;
1880 break;
1881 }
1882 case Attribute.ModulePackages:
1883 case Attribute.ModuleHashes:
1884 break;
1885 default:
1886 throw new IllegalStateException("Unhandled attribute: " +
1887 attrName);
1888 }
1889
1890 return true;
1891 }
1892
1893 private static String getClassName(ClassFile cf, int idx) {
1894 try {
1895 return cf.constant_pool.getClassInfo(idx).getName();
1896 } catch (InvalidIndex ex) {
1897 throw new IllegalStateException(ex);
1898 } catch (ConstantPool.UnexpectedEntry ex) {
1899 throw new IllegalStateException(ex);
1900 } catch (ConstantPoolException ex) {
1901 throw new IllegalStateException(ex);
1902 }
1903 }
1904
2645 }
2646 }
2647 }
2648
2649 public String packge() {
2650 String pack;
2651 int lastSlash = name.lastIndexOf('/');
2652 if (lastSlash != (-1)) {
2653 pack = name.substring(0, lastSlash).replace('/', '.');
2654 } else {
2655 pack = "";
2656 }
2657
2658 return pack;
2659 }
2660 }
2661
2662 static class ClassHeaderDescription extends HeaderDescription {
2663 String extendsAttr;
2664 List<String> implementsAttr;
2665
2666 @Override
2667 public int hashCode() {
2668 int hash = super.hashCode();
2669 hash = 17 * hash + Objects.hashCode(this.extendsAttr);
2670 hash = 17 * hash + Objects.hashCode(this.implementsAttr);
2671 return hash;
2672 }
2673
2674 @Override
2675 public boolean equals(Object obj) {
2676 if (obj == null) {
2677 return false;
2678 }
2679 if (!super.equals(obj)) {
2680 return false;
2681 }
2682 final ClassHeaderDescription other = (ClassHeaderDescription) obj;
2683 if (!Objects.equals(this.extendsAttr, other.extendsAttr)) {
2684 return false;
2685 }
2686 if (!Objects.equals(this.implementsAttr, other.implementsAttr)) {
2687 return false;
2688 }
2689 return true;
2690 }
2691
2692 @Override
2693 public void write(Appendable output, String baselineVersion, String version) throws IOException {
2694 if (!versions.contains(version) ||
2695 (baselineVersion != null && versions.contains(baselineVersion) && versions.contains(version)))
2696 return ;
2697 output.append("header");
2698 if (extendsAttr != null)
2699 output.append(" extends " + extendsAttr);
2700 if (implementsAttr != null && !implementsAttr.isEmpty())
2701 output.append(" implements " + serializeList(implementsAttr));
2702 writeAttributes(output);
2703 output.append("\n");
2704 writeInnerClasses(output, baselineVersion, version);
2705 }
2706
2707 @Override
2708 public boolean read(LineBasedReader reader) throws IOException {
2709 if (!"header".equals(reader.lineKey))
2710 return false;
2711
2712 extendsAttr = reader.attributes.get("extends");
2713 String elementsList = reader.attributes.get("implements");
2714 implementsAttr = deserializeList(elementsList);
2715
2716 readAttributes(reader);
2717 reader.moveNext();
2718 readInnerClasses(reader);
2719
2720 return true;
2721 }
2722
2723 }
2724
2725 static abstract class HeaderDescription extends FeatureDescription {
2726 List<InnerClassInfo> innerClasses;
2727
2728 @Override
2729 public int hashCode() {
2730 int hash = super.hashCode();
2731 hash = 19 * hash + Objects.hashCode(this.innerClasses);
2732 return hash;
2733 }
2734
2735 @Override
3509
3510 ExcludeIncludeList excludeList =
3511 ExcludeIncludeList.create(args[2]);
3512
3513 new CreateSymbols().createBaseLine(versions,
3514 excludeList,
3515 descDest,
3516 args);
3517 break;
3518 }
3519 case "build-description-incremental": {
3520 if (args.length != 3) {
3521 help();
3522 return ;
3523 }
3524
3525 new CreateSymbols().createIncrementalBaseLine(args[1], args[2], args);
3526 break;
3527 }
3528 case "build-ctsym":
3529 if (args.length != 3) {
3530 help();
3531 return ;
3532 }
3533
3534 new CreateSymbols().createSymbols(args[1],
3535 args[2],
3536 CtSymKind.JOINED_VERSIONS);
3537 break;
3538 }
3539 }
3540
3541 }
|
103 import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info;
104 import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
105 import com.sun.tools.classfile.ConstantPool.CPInfo;
106 import com.sun.tools.classfile.ConstantPool.InvalidIndex;
107 import com.sun.tools.classfile.ConstantPoolException;
108 import com.sun.tools.classfile.ConstantValue_attribute;
109 import com.sun.tools.classfile.Deprecated_attribute;
110 import com.sun.tools.classfile.Descriptor;
111 import com.sun.tools.classfile.Exceptions_attribute;
112 import com.sun.tools.classfile.Field;
113 import com.sun.tools.classfile.InnerClasses_attribute;
114 import com.sun.tools.classfile.InnerClasses_attribute.Info;
115 import com.sun.tools.classfile.Method;
116 import com.sun.tools.classfile.ModuleResolution_attribute;
117 import com.sun.tools.classfile.ModuleTarget_attribute;
118 import com.sun.tools.classfile.Module_attribute;
119 import com.sun.tools.classfile.Module_attribute.ExportsEntry;
120 import com.sun.tools.classfile.Module_attribute.OpensEntry;
121 import com.sun.tools.classfile.Module_attribute.ProvidesEntry;
122 import com.sun.tools.classfile.Module_attribute.RequiresEntry;
123 import com.sun.tools.classfile.NestHost_attribute;
124 import com.sun.tools.classfile.NestMembers_attribute;
125 import com.sun.tools.classfile.RuntimeAnnotations_attribute;
126 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
127 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
128 import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute;
129 import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
130 import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
131 import com.sun.tools.classfile.Signature_attribute;
132 import com.sun.tools.javac.api.JavacTool;
133 import com.sun.tools.javac.jvm.Target;
134 import com.sun.tools.javac.util.Assert;
135 import com.sun.tools.javac.util.Context;
136 import com.sun.tools.javac.util.Pair;
137
138 /**
139 * A tool for processing the .sym.txt files.
140 *
141 * To add historical data for JDK N, N >= 11, do the following:
142 * * cd <open-jdk-checkout>/make/data/symbols
143 * * <jdk-N>/bin/java --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
144 * --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
145 * --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \
146 * --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
147 * --add-modules jdk.jdeps \
148 * ../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \
149 * build-description-incremental symbols include.list
150 * * sanity-check the new and updates files in make/data/symbols and commit them
151 *
152 * The tools allows to:
153 * * convert the .sym.txt into class/sig files for ct.sym
154 * * in cooperation with the adjacent history Probe, construct .sym.txt files for previous platforms
155 * * enhance existing .sym.txt files with a a new set .sym.txt for the current platform
156 *
157 * To convert the .sym.txt files to class/sig files from ct.sym, run:
158 * java build.tool.symbolgenerator.CreateSymbols build-ctsym <platform-description-file> <target-directory>
159 *
160 * The <platform-description-file> is a file of this format:
161 * generate platforms <platform-ids-to-generate separate with ':'>
162 * platform version <platform-id1> files <.sym.txt files containing history data for given platform, separate with ':'>
163 * platform version <platform-id2> base <base-platform-id> files <.sym.txt files containing history data for given platform, separate with ':'>
164 *
165 * The content of platform "<base-platform-id>" is also automatically added to the content of
166 * platform "<platform-id2>", unless explicitly excluded in "<platform-id2>"'s .sym.txt files.
167 *
168 * To create the .sym.txt files, first run the history Probe for all the previous platforms:
169 * <jdk-N>/bin/java build.tools.symbolgenerator.Probe <classes-for-N>
170 *
171 * Where <classes-for-N> is a name of a file into which the classes from the bootclasspath of <jdk-N>
172 * will be written.
184 * Several include list files may be specified, separated by File.pathSeparator.
185 *
186 * When <diff-against-platformN> is specified, the .sym.txt files for platform N will only contain
187 * differences between platform N and the specified platform. The first platform (denoted F further)
188 * that is specified should use literal value "<none>", to have all the APIs of the platform written to
189 * the .sym.txt files. If there is an existing platform with full .sym.txt files in the repository,
190 * that platform should be used as the first platform to avoid unnecessary changes to the .sym.txt
191 * files. The <diff-against-platformN> for platform N should be determined as follows: if N < F, then
192 * <diff-against-platformN> should be N + 1. If F < N, then <diff-against-platformN> should be N - 1.
193 * If N is a custom/specialized sub-version of another platform N', then <diff-against-platformN> should be N'.
194 *
195 * To generate the .sym.txt files for OpenJDK 7 and 8:
196 * <jdk-7>/bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes
197 * <jdk-8>/bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes
198 * java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list
199 * 8 OpenJDK8.classes '<none>'
200 * 7 OpenJDK7.classes 8
201 *
202 * Note: the versions are expected to be a single character.
203 *
204 */
205 public class CreateSymbols {
206
207 //<editor-fold defaultstate="collapsed" desc="ct.sym construction">
208 /**Create sig files for ct.sym reading the classes description from the directory that contains
209 * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
210 */
211 @SuppressWarnings("unchecked")
212 public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFile, String ctSymLocation, CtSymKind ctSymKind) throws IOException {
213 LoadDescriptions data = load(Paths.get(ctDescriptionFileExtra), Paths.get(ctDescriptionFile), null);
214
215 splitHeaders(data.classes);
216
217 for (ModuleDescription md : data.modules.values()) {
218 for (ModuleHeaderDescription mhd : md.header) {
219 List<String> versionsList =
220 Collections.singletonList(mhd.versions);
221 writeModulesForVersions(ctSymLocation,
222 md,
223 mhd,
224 versionsList);
225 }
226 }
227
228 for (ClassDescription classDescription : data.classes) {
229 for (ClassHeaderDescription header : classDescription.header) {
230 switch (ctSymKind) {
231 case JOINED_VERSIONS:
232 Set<String> jointVersions = new HashSet<>();
233 jointVersions.add(header.versions);
234 limitJointVersion(jointVersions, classDescription.fields);
235 limitJointVersion(jointVersions, classDescription.methods);
236 writeClassesForVersions(ctSymLocation, classDescription, header, jointVersions);
237 break;
238 case SEPARATE:
239 Set<String> versions = new HashSet<>();
240 for (char v : header.versions.toCharArray()) {
241 versions.add("" + v);
242 }
243 writeClassesForVersions(ctSymLocation, classDescription, header, versions);
244 break;
245 }
246 }
247 }
248 }
249
250 public static String EXTENSION = ".sig";
251
252 LoadDescriptions load(Path ctDescriptionWithExtraContent, Path ctDescriptionOpen, String deletePlatform) throws IOException {
253 Map<String, PlatformInput> platforms = new LinkedHashMap<>();
254
255 if (ctDescriptionWithExtraContent != null && Files.isRegularFile(ctDescriptionWithExtraContent)) {
256 try (LineBasedReader reader = new LineBasedReader(ctDescriptionWithExtraContent)) {
257 while (reader.hasNext()) {
258 switch (reader.lineKey) {
259 case "generate":
260 //ignore
261 reader.moveNext();
262 break;
263 case "platform":
264 PlatformInput platform = PlatformInput.load(ctDescriptionWithExtraContent,
265 reader);
266 if (!platform.version.equals(deletePlatform))
267 platforms.put(platform.version, platform);
268 reader.moveNext();
269 break;
270 default:
271 throw new IllegalStateException("Unknown key: " + reader.lineKey);
272 }
273 }
274 }
275 }
276
277 Set<String> generatePlatforms = null;
278
279 try (LineBasedReader reader = new LineBasedReader(ctDescriptionOpen)) {
280 while (reader.hasNext()) {
281 switch (reader.lineKey) {
282 case "generate":
283 String[] platformsAttr = reader.attributes.get("platforms").split(":");
284 generatePlatforms = new HashSet<>(List.of(platformsAttr));
285 generatePlatforms.remove(deletePlatform);
286 reader.moveNext();
287 break;
288 case "platform":
289 PlatformInput platform = PlatformInput.load(ctDescriptionOpen, reader);
290 if (!platform.version.equals(deletePlatform) &&
291 !platforms.containsKey(platform.version))
292 platforms.put(platform.version, platform);
293 reader.moveNext();
294 break;
295 default:
296 throw new IllegalStateException("Unknown key: " + reader.lineKey);
297 }
298 }
299 }
300
301 Map<String, ClassDescription> classes = new LinkedHashMap<>();
302 Map<String, ModuleDescription> modules = new LinkedHashMap<>();
303
304 for (PlatformInput platform : platforms.values()) {
305 for (ClassDescription cd : classes.values()) {
306 addNewVersion(cd.header, platform.basePlatform, platform.version);
307 addNewVersion(cd.fields, platform.basePlatform, platform.version);
308 addNewVersion(cd.methods, platform.basePlatform, platform.version);
309 }
310 for (ModuleDescription md : modules.values()) {
311 addNewVersion(md.header, platform.basePlatform, platform.version);
312 }
313 for (String input : platform.files) {
314 Path inputFile = platform.ctDescription.getParent().resolve(input);
315 try (LineBasedReader reader = new LineBasedReader(inputFile)) {
316 while (reader.hasNext()) {
317 String nameAttr = reader.attributes.get("name");
318 switch (reader.lineKey) {
319 case "class": case "-class":
320 ClassDescription cd =
321 classes.computeIfAbsent(nameAttr,
322 n -> new ClassDescription());
323 if ("-class".equals(reader.lineKey)) {
324 removeVersion(cd.header, h -> true,
325 platform.version);
326 reader.moveNext();
327 continue;
328 }
329 cd.read(reader, platform.basePlatform,
330 platform.version);
331 break;
332 case "module": {
333 ModuleDescription md =
334 modules.computeIfAbsent(nameAttr,
395 Map<String, ModuleDescription> moduleList = new HashMap<>();
396
397 for (ModuleDescription desc : modules.values()) {
398 Iterator<ModuleHeaderDescription> mhdIt = desc.header.iterator();
399
400 while (mhdIt.hasNext()) {
401 ModuleHeaderDescription mhd = mhdIt.next();
402
403 mhd.versions = reduce(mhd.versions, generatePlatforms);
404 if (mhd.versions.isEmpty())
405 mhdIt.remove();
406 }
407
408 if (desc.header.isEmpty()) {
409 continue;
410 }
411
412 moduleList.put(desc.name, desc);
413 }
414
415 return new LoadDescriptions(result, moduleList, new ArrayList<>(platforms.values()));
416 }
417
418 static final class LoadDescriptions {
419 public final ClassList classes;
420 public final Map<String, ModuleDescription> modules;
421 public final List<PlatformInput> versions;
422
423 public LoadDescriptions(ClassList classes,
424 Map<String, ModuleDescription> modules,
425 List<PlatformInput> versions) {
426 this.classes = classes;
427 this.modules = modules;
428 this.versions = versions;
429 }
430
431 }
432
433 static final class LineBasedReader implements AutoCloseable {
434 private final BufferedReader input;
435 public String lineKey;
481 }
482
483 return reduce(original, otherSet);
484 }
485
486 private static String reduce(String original, Set<String> generate) {
487 StringBuilder sb = new StringBuilder();
488
489 for (char v : original.toCharArray()) {
490 if (generate.contains("" + v)) {
491 sb.append(v);
492 }
493 }
494 return sb.toString();
495 }
496
497 private static class PlatformInput {
498 public final String version;
499 public final String basePlatform;
500 public final List<String> files;
501 public final Path ctDescription;
502 public PlatformInput(Path ctDescription, String version, String basePlatform, List<String> files) {
503 this.ctDescription = ctDescription;
504 this.version = version;
505 this.basePlatform = basePlatform;
506 this.files = files;
507 }
508
509 public static PlatformInput load(Path ctDescription, LineBasedReader in) throws IOException {
510 return new PlatformInput(ctDescription,
511 in.attributes.get("version"),
512 in.attributes.get("base"),
513 List.of(in.attributes.get("files").split(":")));
514 }
515 }
516
517 static void addNewVersion(Collection<? extends FeatureDescription> features,
518 String baselineVersion,
519 String version) {
520 features.stream()
521 .filter(f -> f.versions.contains(baselineVersion))
522 .forEach(f -> f.versions += version);
523 }
524
525 static <T extends FeatureDescription> void removeVersion(Collection<T> features,
526 Predicate<T> shouldRemove,
527 String version) {
528 for (T existing : features) {
529 if (shouldRemove.test(existing) && existing.versions.endsWith(version)) {
530 existing.versions = existing.versions.replace(version, "");
531 return;
839 String e) {
840 return new ExportsEntry(addPackageName(cp, e), 0, new int[0]);
841 }
842
843 private static OpensEntry createOpensEntry(List<CPInfo> cp, String e) {
844 return new OpensEntry(addPackageName(cp, e), 0, new int[0]);
845 }
846
847 private static ProvidesEntry createProvidesEntry(List<CPInfo> cp,
848 ModuleHeaderDescription.ProvidesDescription p) {
849 final int idx = addClassName(cp, p.interfaceName);
850 return new ProvidesEntry(idx, p.implNames
851 .stream()
852 .mapToInt(i -> addClassName(cp, i))
853 .toArray());
854 }
855
856 private void addAttributes(ClassHeaderDescription header,
857 List<CPInfo> constantPool, Map<String, Attribute> attributes) {
858 addGenericAttributes(header, constantPool, attributes);
859 if (header.nestHost != null) {
860 int attributeString = addString(constantPool, Attribute.NestHost);
861 int nestHost = addClass(constantPool, header.nestHost);
862 attributes.put(Attribute.NestHost,
863 new NestHost_attribute(attributeString, nestHost));
864 }
865 if (header.nestMembers != null && !header.nestMembers.isEmpty()) {
866 int attributeString = addString(constantPool, Attribute.NestMembers);
867 int[] nestMembers = new int[header.nestMembers.size()];
868 int i = 0;
869 for (String intf : header.nestMembers) {
870 nestMembers[i++] = addClass(constantPool, intf);
871 }
872 attributes.put(Attribute.NestMembers,
873 new NestMembers_attribute(attributeString, nestMembers));
874 }
875 addInnerClassesAttribute(header, constantPool, attributes);
876 }
877
878 private void addInnerClassesAttribute(HeaderDescription header,
879 List<CPInfo> constantPool, Map<String, Attribute> attributes) {
880 if (header.innerClasses != null && !header.innerClasses.isEmpty()) {
881 Info[] innerClasses = new Info[header.innerClasses.size()];
882 int i = 0;
883 for (InnerClassInfo info : header.innerClasses) {
884 innerClasses[i++] =
885 new Info(info.innerClass == null ? 0 : addClass(constantPool, info.innerClass),
886 info.outerClass == null ? 0 : addClass(constantPool, info.outerClass),
887 info.innerClassName == null ? 0 : addString(constantPool, info.innerClassName),
888 new AccessFlags(info.innerClassFlags));
889 }
890 int attributeString = addString(constantPool, Attribute.InnerClasses);
891 attributes.put(Attribute.InnerClasses,
892 new InnerClasses_attribute(attributeString, innerClasses));
893 }
894 }
1189 try (BufferedReader descIn =
1190 Files.newBufferedReader(Paths.get(desc.classes))) {
1191 String line;
1192 while ((line = descIn.readLine()) != null) {
1193 ByteArrayOutputStream data = new ByteArrayOutputStream();
1194 for (int i = 0; i < line.length(); i += 2) {
1195 String hex = line.substring(i, i + 2);
1196 data.write(Integer.parseInt(hex, 16));
1197 }
1198 classFileData.add(data.toByteArray());
1199 }
1200 } catch (IOException ex) {
1201 throw new IllegalStateException(ex);
1202 }
1203
1204 loadVersionClasses(classes, modules, classFileData, excludesIncludes, desc.version);
1205 }
1206
1207 List<PlatformInput> platforms =
1208 versions.stream()
1209 .map(desc -> new PlatformInput(null,
1210 desc.version,
1211 desc.primaryBaseline,
1212 null))
1213 .collect(Collectors.toList());
1214
1215 dumpDescriptions(classes, modules, platforms, descDest.resolve("symbols"), args);
1216 }
1217 //where:
1218 private static final String DO_NO_MODIFY =
1219 "#\n" +
1220 "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" +
1221 "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" +
1222 "#\n" +
1223 "# This code is free software; you can redistribute it and/or modify it\n" +
1224 "# under the terms of the GNU General Public License version 2 only, as\n" +
1225 "# published by the Free Software Foundation. Oracle designates this\n" +
1226 "# particular file as subject to the \"Classpath\" exception as provided\n" +
1227 "# by Oracle in the LICENSE file that accompanied this code.\n" +
1228 "#\n" +
1229 "# This code is distributed in the hope that it will be useful, but WITHOUT\n" +
1230 "# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +
1333 currentVersionClasses);
1334 modified |= includeOutputType(clazz.fields,
1335 f -> f.descriptor,
1336 includedClasses,
1337 currentVersionClasses);
1338 modified |= includeOutputType(clazz.methods,
1339 m -> m.descriptor,
1340 includedClasses,
1341 currentVersionClasses);
1342 }
1343 }
1344 } while (modified);
1345
1346 for (ClassDescription clazz : currentVersionClasses) {
1347 if (!includedClasses.contains(clazz.name)) {
1348 continue;
1349 }
1350
1351 ClassHeaderDescription header = clazz.header.get(0);
1352
1353 if (header.nestMembers != null) {
1354 Iterator<String> nestMemberIt = header.nestMembers.iterator();
1355
1356 while(nestMemberIt.hasNext()) {
1357 String member = nestMemberIt.next();
1358 if (!includedClasses.contains(member))
1359 nestMemberIt.remove();
1360 }
1361 }
1362
1363 if (header.innerClasses != null) {
1364 Iterator<InnerClassInfo> innerClassIt = header.innerClasses.iterator();
1365
1366 while(innerClassIt.hasNext()) {
1367 InnerClassInfo ici = innerClassIt.next();
1368 if (!includedClasses.contains(ici.innerClass))
1369 innerClassIt.remove();
1370 }
1371 }
1372
1373 ClassDescription existing = classes.find(clazz.name, true);
1374
1375 if (existing != null) {
1376 addClassHeader(existing, header, version);
1377 for (MethodDescription currentMethod : clazz.methods) {
1378 addMethod(existing, currentMethod, version);
1379 }
1380 for (FieldDescription currentField : clazz.fields) {
1381 addField(existing, currentField, version);
1382 }
1404 if (existing != null) {
1405 addModuleHeader(existing, header, version);
1406 } else {
1407 modules.put(module.name, module);
1408 }
1409 }
1410 }
1411 //where:
1412 private static final String PROPERITARY_ANNOTATION =
1413 "Lsun/Proprietary+Annotation;";
1414
1415 private void dumpDescriptions(ClassList classes,
1416 Map<String, ModuleDescription> modules,
1417 List<PlatformInput> versions,
1418 Path ctDescriptionFile,
1419 String[] args) throws IOException {
1420 classes.sort();
1421
1422 Map<String, String> package2Modules = new HashMap<>();
1423
1424 versions.stream()
1425 .filter(v -> "9".compareTo(v.version) <= 0)
1426 .sorted((v1, v2) -> v1.version.compareTo(v2.version))
1427 .forEach(v -> {
1428 for (ModuleDescription md : modules.values()) {
1429 md.header
1430 .stream()
1431 .filter(h -> h.versions.contains(v.version))
1432 .flatMap(h -> h.exports.stream())
1433 .map(p -> p.replace('/', '.'))
1434 .forEach(p -> package2Modules.putIfAbsent(p, md.name));
1435 }
1436 });
1437
1438 package2Modules.put("java.awt.dnd.peer", "java.desktop");
1439 package2Modules.put("java.awt.peer", "java.desktop");
1440 package2Modules.put("jdk", "java.base");
1441
1442 Map<String, List<ClassDescription>> module2Classes = new HashMap<>();
1443
1444 for (ClassDescription clazz : classes) {
1445 String pack = clazz.packge();
1446 String module = package2Modules.get(pack);
1447
1448 if (module == null) {
1449 module = "java.base";
1450
1451 OUTER: while (!pack.isEmpty()) {
1452 for (Entry<String, String> p2M : package2Modules.entrySet()) {
1453 if (p2M.getKey().startsWith(pack)) {
1454 module = p2M.getValue();
1455 break OUTER;
1456 }
1534 }
1535 symbolsOut.append(" files ")
1536 .append(versionFileEntry.getValue()
1537 .stream()
1538 .map(p -> p)
1539 .sorted()
1540 .collect(Collectors.joining(":")))
1541 .append("\n");
1542 }
1543 }
1544 }
1545
1546 public void createIncrementalBaseLine(String ctDescriptionFile,
1547 String excludeFile,
1548 String[] args) throws IOException {
1549 String specVersion = System.getProperty("java.specification.version");
1550 String currentVersion =
1551 Integer.toString(Integer.parseInt(specVersion), Character.MAX_RADIX);
1552 currentVersion = currentVersion.toUpperCase(Locale.ROOT);
1553 Path ctDescriptionPath = Paths.get(ctDescriptionFile).toAbsolutePath();
1554 LoadDescriptions data = load(null, ctDescriptionPath, currentVersion);
1555
1556 ClassList classes = data.classes;
1557 Map<String, ModuleDescription> modules = data.modules;
1558 List<PlatformInput> versions = data.versions;
1559
1560 ExcludeIncludeList excludeList =
1561 ExcludeIncludeList.create(excludeFile);
1562
1563 Iterable<byte[]> classBytes = dumpCurrentClasses();
1564 loadVersionClasses(classes, modules, classBytes, excludeList, currentVersion);
1565
1566 String baseline;
1567
1568 if (versions.isEmpty()) {
1569 baseline = null;
1570 } else {
1571 baseline = versions.stream()
1572 .sorted((v1, v2) -> v2.version.compareTo(v1.version))
1573 .findFirst()
1574 .get()
1575 .version;
1576 }
1577
1578 versions.add(new PlatformInput(null, currentVersion, baseline, null));
1579 dumpDescriptions(classes, modules, versions, ctDescriptionPath, args);
1580 }
1581
1582 private List<byte[]> dumpCurrentClasses() throws IOException {
1583 JavacTool tool = JavacTool.create();
1584 Context ctx = new Context();
1585 String version = System.getProperty("java.specification.version");
1586 JavacTask task = tool.getTask(null, null, null,
1587 List.of("--release", version),
1588 null, null, ctx);
1589 task.getElements().getTypeElement("java.lang.Object");
1590 JavaFileManager fm = ctx.get(JavaFileManager.class);
1591
1592 List<byte[]> data = new ArrayList<>();
1593 for (Location modLoc : LOCATIONS) {
1594 for (Set<JavaFileManager.Location> module :
1595 fm.listLocationsForModules(modLoc)) {
1596 for (JavaFileManager.Location loc : module) {
1597 Iterable<JavaFileObject> files =
1598 fm.list(loc,
1936 ModuleTarget_attribute mod = (ModuleTarget_attribute) attr;
1937 if (mod.target_platform_index != 0) {
1938 header.moduleTarget =
1939 cf.constant_pool
1940 .getUTF8Value(mod.target_platform_index);
1941 }
1942 break;
1943 }
1944 case Attribute.ModuleResolution: {
1945 assert feature instanceof ModuleHeaderDescription;
1946 ModuleHeaderDescription header =
1947 (ModuleHeaderDescription) feature;
1948 ModuleResolution_attribute mod =
1949 (ModuleResolution_attribute) attr;
1950 header.moduleResolution = mod.resolution_flags;
1951 break;
1952 }
1953 case Attribute.ModulePackages:
1954 case Attribute.ModuleHashes:
1955 break;
1956 case Attribute.NestHost: {
1957 assert feature instanceof ClassHeaderDescription;
1958 NestHost_attribute nestHost = (NestHost_attribute) attr;
1959 ClassHeaderDescription chd = (ClassHeaderDescription) feature;
1960 chd.nestHost = nestHost.getNestTop(cf.constant_pool).getName();
1961 break;
1962 }
1963 case Attribute.NestMembers: {
1964 assert feature instanceof ClassHeaderDescription;
1965 NestMembers_attribute nestMembers = (NestMembers_attribute) attr;
1966 ClassHeaderDescription chd = (ClassHeaderDescription) feature;
1967 chd.nestMembers = Arrays.stream(nestMembers.members_indexes)
1968 .mapToObj(i -> getClassName(cf, i))
1969 .collect(Collectors.toList());
1970 break;
1971 }
1972 default:
1973 throw new IllegalStateException("Unhandled attribute: " +
1974 attrName);
1975 }
1976
1977 return true;
1978 }
1979
1980 private static String getClassName(ClassFile cf, int idx) {
1981 try {
1982 return cf.constant_pool.getClassInfo(idx).getName();
1983 } catch (InvalidIndex ex) {
1984 throw new IllegalStateException(ex);
1985 } catch (ConstantPool.UnexpectedEntry ex) {
1986 throw new IllegalStateException(ex);
1987 } catch (ConstantPoolException ex) {
1988 throw new IllegalStateException(ex);
1989 }
1990 }
1991
2732 }
2733 }
2734 }
2735
2736 public String packge() {
2737 String pack;
2738 int lastSlash = name.lastIndexOf('/');
2739 if (lastSlash != (-1)) {
2740 pack = name.substring(0, lastSlash).replace('/', '.');
2741 } else {
2742 pack = "";
2743 }
2744
2745 return pack;
2746 }
2747 }
2748
2749 static class ClassHeaderDescription extends HeaderDescription {
2750 String extendsAttr;
2751 List<String> implementsAttr;
2752 String nestHost;
2753 List<String> nestMembers;
2754
2755 @Override
2756 public int hashCode() {
2757 int hash = super.hashCode();
2758 hash = 17 * hash + Objects.hashCode(this.extendsAttr);
2759 hash = 17 * hash + Objects.hashCode(this.implementsAttr);
2760 hash = 17 * hash + Objects.hashCode(this.nestHost);
2761 hash = 17 * hash + Objects.hashCode(this.nestMembers);
2762 return hash;
2763 }
2764
2765 @Override
2766 public boolean equals(Object obj) {
2767 if (obj == null) {
2768 return false;
2769 }
2770 if (!super.equals(obj)) {
2771 return false;
2772 }
2773 final ClassHeaderDescription other = (ClassHeaderDescription) obj;
2774 if (!Objects.equals(this.extendsAttr, other.extendsAttr)) {
2775 return false;
2776 }
2777 if (!Objects.equals(this.implementsAttr, other.implementsAttr)) {
2778 return false;
2779 }
2780 if (!Objects.equals(this.nestHost, other.nestHost)) {
2781 return false;
2782 }
2783 if (!Objects.equals(this.nestMembers, other.nestMembers)) {
2784 return false;
2785 }
2786 return true;
2787 }
2788
2789 @Override
2790 public void write(Appendable output, String baselineVersion, String version) throws IOException {
2791 if (!versions.contains(version) ||
2792 (baselineVersion != null && versions.contains(baselineVersion) && versions.contains(version)))
2793 return ;
2794 output.append("header");
2795 if (extendsAttr != null)
2796 output.append(" extends " + extendsAttr);
2797 if (implementsAttr != null && !implementsAttr.isEmpty())
2798 output.append(" implements " + serializeList(implementsAttr));
2799 if (nestHost != null)
2800 output.append(" nestHost " + nestHost);
2801 if (nestMembers != null && !nestMembers.isEmpty())
2802 output.append(" nestMembers " + serializeList(nestMembers));
2803 writeAttributes(output);
2804 output.append("\n");
2805 writeInnerClasses(output, baselineVersion, version);
2806 }
2807
2808 @Override
2809 public boolean read(LineBasedReader reader) throws IOException {
2810 if (!"header".equals(reader.lineKey))
2811 return false;
2812
2813 extendsAttr = reader.attributes.get("extends");
2814 String elementsList = reader.attributes.get("implements");
2815 implementsAttr = deserializeList(elementsList);
2816
2817 nestHost = reader.attributes.get("nestHost");
2818 String nestMembersList = reader.attributes.get("nestMembers");
2819 nestMembers = deserializeList(nestMembersList);
2820
2821 readAttributes(reader);
2822 reader.moveNext();
2823 readInnerClasses(reader);
2824
2825 return true;
2826 }
2827
2828 }
2829
2830 static abstract class HeaderDescription extends FeatureDescription {
2831 List<InnerClassInfo> innerClasses;
2832
2833 @Override
2834 public int hashCode() {
2835 int hash = super.hashCode();
2836 hash = 19 * hash + Objects.hashCode(this.innerClasses);
2837 return hash;
2838 }
2839
2840 @Override
3614
3615 ExcludeIncludeList excludeList =
3616 ExcludeIncludeList.create(args[2]);
3617
3618 new CreateSymbols().createBaseLine(versions,
3619 excludeList,
3620 descDest,
3621 args);
3622 break;
3623 }
3624 case "build-description-incremental": {
3625 if (args.length != 3) {
3626 help();
3627 return ;
3628 }
3629
3630 new CreateSymbols().createIncrementalBaseLine(args[1], args[2], args);
3631 break;
3632 }
3633 case "build-ctsym":
3634 if (args.length != 4) {
3635 help();
3636 return ;
3637 }
3638
3639 new CreateSymbols().createSymbols(args[1],
3640 args[2],
3641 args[3],
3642 CtSymKind.JOINED_VERSIONS);
3643 break;
3644 }
3645 }
3646
3647 }
|