< prev index next >

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

Print this page


   1 /*
   2  * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  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


  41 import java.nio.file.Paths;
  42 import java.nio.file.attribute.BasicFileAttributes;
  43 import java.util.stream.Stream;
  44 import java.util.ArrayList;
  45 import java.util.Arrays;
  46 import java.util.Collection;
  47 import java.util.Collections;
  48 import java.util.HashMap;
  49 import java.util.HashSet;
  50 import java.util.Iterator;
  51 import java.util.LinkedHashMap;
  52 import java.util.List;
  53 import java.util.Map;
  54 import java.util.Map.Entry;
  55 import java.util.Objects;
  56 import java.util.Set;
  57 import java.util.function.Function;
  58 import java.util.function.Predicate;
  59 import java.util.regex.Matcher;
  60 import java.util.regex.Pattern;

  61 
  62 import com.sun.tools.classfile.AccessFlags;
  63 import com.sun.tools.classfile.Annotation;
  64 import com.sun.tools.classfile.Annotation.Annotation_element_value;
  65 import com.sun.tools.classfile.Annotation.Array_element_value;
  66 import com.sun.tools.classfile.Annotation.Class_element_value;
  67 import com.sun.tools.classfile.Annotation.Enum_element_value;
  68 import com.sun.tools.classfile.Annotation.Primitive_element_value;
  69 import com.sun.tools.classfile.Annotation.element_value;
  70 import com.sun.tools.classfile.Annotation.element_value_pair;
  71 import com.sun.tools.classfile.AnnotationDefault_attribute;
  72 import com.sun.tools.classfile.Attribute;
  73 import com.sun.tools.classfile.Attributes;
  74 import com.sun.tools.classfile.ClassFile;
  75 import com.sun.tools.classfile.ClassWriter;
  76 import com.sun.tools.classfile.ConstantPool;
  77 import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
  78 import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
  79 import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info;
  80 import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info;


 103 import com.sun.tools.javac.util.Assert;
 104 import com.sun.tools.javac.util.Pair;
 105 
 106 /**
 107  * A tool for processing the .sym.txt files. It allows to:
 108  *  * convert the .sym.txt into class/sig files for ct.sym
 109  *  * in cooperation with the adjacent history Probe, construct .sym.txt files for previous platforms
 110  *
 111  * To convert the .sym.txt files to class/sig files from ct.sym, run:
 112  *     java build.tool.symbolgenerator.CreateSymbols build-ctsym [JOINED_VERSIONS|SEPARATE] <platform-description-file> <target-directory>
 113  *
 114  * The <platform-description-file> is a file of this format:
 115  *     generate platforms <platform-ids-to-generate separate with ':'>
 116  *     platform version <platform-id1> files <.sym.txt files containing history data for given platform, separate with ':'>
 117  *     platform version <platform-id2> base <base-platform-id> files <.sym.txt files containing history data for given platform, separate with ':'>
 118  *
 119  * The content of platform "<base-platform-id>" is also automatically added to the content of
 120  * platform "<platform-id2>", unless explicitly excluded in "<platform-id2>"'s .sym.txt files.
 121  *
 122  * To create the .sym.txt files, first run the history Probe for all the previous platforms:
 123  *     java build.tools.symbolgenerator.Probe <target-file-for-platform>



 124  *
 125  * Then create the .sym.txt files like this:
 126  *     java build.tools.symbolgenerator.CreateSymbols build-description <target-directory> <path-to-a-JDK-root> <include-list-file>
 127  *                                                    <platform-id1> <target-file-for-platform1> "<none>"
 128  *                                                    <platform-id2> <target-file-for-platform2> <diff-against-platform2>
 129  *                                                    <platform-id3> <target-file-for-platform3> <diff-against-platform3>
 130  *                                                    ...
 131  *
 132  * The <include-list-file> is a file that specifies classes that should be included/excluded.
 133  * Lines that start with '+' represent class or package that should be included, '-' class or package
 134  * that should be excluded. '/' should be used as package name delimiter, packages should end with '/'.
 135  * Several include list files may be specified, separated by File.pathSeparator.
 136  *
 137  * When <diff-against-platformN> is specified, the .sym.txt files for platform N will only contain
 138  * differences between platform N and the specified platform. The first platform (denoted F further)
 139  * that is specified should use literal value "<none>", to have all the APIs of the platform written to
 140  * the .sym.txt files. If there is an existing platform with full .sym.txt files in the repository,
 141  * that platform should be used as the first platform to avoid unnecessary changes to the .sym.txt
 142  * files. The <diff-against-platformN> for platform N should be determined as follows: if N < F, then
 143  * <diff-against-platformN> should be N + 1. If F < N, then <diff-against-platformN> should be N - 1.
 144  * If N is a custom/specialized sub-version of another platform N', then <diff-against-platformN> should be N'.
 145  *
 146  * To generate the .sym.txt files for OpenJDK 7 and 8:


 147  *     java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list
 148  *                                                    8 OpenJDK8.classes '<none>'
 149  *                                                    7 OpenJDK7.classes 8
 150  *
 151  * Note: the versions are expected to be a single character.
 152  */
 153 public class CreateSymbols {
 154 
 155     //<editor-fold defaultstate="collapsed" desc="ct.sym construction">
 156     /**Create sig files for ct.sym reading the classes description from the directory that contains
 157      * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
 158      */
 159     @SuppressWarnings("unchecked")
 160     public void createSymbols(String ctDescriptionFile, String ctSymLocation, CtSymKind ctSymKind) throws IOException {
 161         ClassList classes = load(Paths.get(ctDescriptionFile));
 162 
 163         splitHeaders(classes);
 164 
 165         for (ClassDescription classDescription : classes) {
 166             for (ClassHeaderDescription header : classDescription.header) {


 896         Map<String, String> package2Modules = buildPackage2Modules(jdkRoot);
 897         Map<String, List<ClassDescription>> module2Classes = new HashMap<>();
 898 
 899         for (ClassDescription clazz : classes) {
 900             String pack;
 901             int lastSlash = clazz.name.lastIndexOf('/');
 902             if (lastSlash != (-1)) {
 903                 pack = clazz.name.substring(0, lastSlash).replace('/', '.');
 904             } else {
 905                 pack = "";
 906             }
 907             String module = package2Modules.get(pack);
 908 
 909             if (module == null) {
 910                 module = "java.base";
 911 
 912                 OUTER: while (!pack.isEmpty()) {
 913                     for (Entry<String, String> p2M : package2Modules.entrySet()) {
 914                         if (p2M.getKey().startsWith(pack)) {
 915                             module = p2M.getValue();
 916                             break;
 917                         }
 918                     }
 919                     int dot = pack.lastIndexOf('.');
 920                     if (dot == (-1))
 921                         break;
 922                     pack = pack.substring(0, dot);
 923                 }
 924             }
 925             module2Classes.computeIfAbsent(module, m -> new ArrayList<>())
 926                     .add(clazz);
 927         }
 928 







 929         for (Entry<String, List<ClassDescription>> e : module2Classes.entrySet()) {
 930             for (VersionDescription desc : versions) {
 931                 Path f = descDest.resolve(e.getKey() + "-" + desc.version + ".sym.txt");
 932                 Files.createDirectories(f.getParent());
 933                 try (Writer out = Files.newBufferedWriter(f)) {
 934                     for (ClassDescription clazz : e.getValue()) {
 935                         clazz.write(out, desc.primaryBaseline, desc.version);
 936                     }
 937                 }























 938             }
 939         }
 940     }
 941 
 942     //<editor-fold defaultstate="collapsed" desc="Class Reading">
 943     //non-final for tests:
 944     public static String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;";
 945     public static boolean ALLOW_NON_EXISTING_CLASSES = false;
 946 
 947     private void inspectClassFile(InputStream in, ClassList classes, ExcludeIncludeList excludesIncludes, String version) throws IOException, ConstantPoolException {
 948         ClassFile cf = ClassFile.read(in);
 949 
 950         if (!excludesIncludes.accepts(cf.getName())) {
 951             return ;
 952         }
 953 
 954         ClassHeaderDescription headerDesc = new ClassHeaderDescription();
 955 
 956         headerDesc.flags = cf.access_flags.flags;
 957 


   1 /*
   2  * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  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


  41 import java.nio.file.Paths;
  42 import java.nio.file.attribute.BasicFileAttributes;
  43 import java.util.stream.Stream;
  44 import java.util.ArrayList;
  45 import java.util.Arrays;
  46 import java.util.Collection;
  47 import java.util.Collections;
  48 import java.util.HashMap;
  49 import java.util.HashSet;
  50 import java.util.Iterator;
  51 import java.util.LinkedHashMap;
  52 import java.util.List;
  53 import java.util.Map;
  54 import java.util.Map.Entry;
  55 import java.util.Objects;
  56 import java.util.Set;
  57 import java.util.function.Function;
  58 import java.util.function.Predicate;
  59 import java.util.regex.Matcher;
  60 import java.util.regex.Pattern;
  61 import java.util.stream.Collectors;
  62 
  63 import com.sun.tools.classfile.AccessFlags;
  64 import com.sun.tools.classfile.Annotation;
  65 import com.sun.tools.classfile.Annotation.Annotation_element_value;
  66 import com.sun.tools.classfile.Annotation.Array_element_value;
  67 import com.sun.tools.classfile.Annotation.Class_element_value;
  68 import com.sun.tools.classfile.Annotation.Enum_element_value;
  69 import com.sun.tools.classfile.Annotation.Primitive_element_value;
  70 import com.sun.tools.classfile.Annotation.element_value;
  71 import com.sun.tools.classfile.Annotation.element_value_pair;
  72 import com.sun.tools.classfile.AnnotationDefault_attribute;
  73 import com.sun.tools.classfile.Attribute;
  74 import com.sun.tools.classfile.Attributes;
  75 import com.sun.tools.classfile.ClassFile;
  76 import com.sun.tools.classfile.ClassWriter;
  77 import com.sun.tools.classfile.ConstantPool;
  78 import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
  79 import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
  80 import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info;
  81 import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info;


 104 import com.sun.tools.javac.util.Assert;
 105 import com.sun.tools.javac.util.Pair;
 106 
 107 /**
 108  * A tool for processing the .sym.txt files. It allows to:
 109  *  * convert the .sym.txt into class/sig files for ct.sym
 110  *  * in cooperation with the adjacent history Probe, construct .sym.txt files for previous platforms
 111  *
 112  * To convert the .sym.txt files to class/sig files from ct.sym, run:
 113  *     java build.tool.symbolgenerator.CreateSymbols build-ctsym [JOINED_VERSIONS|SEPARATE] <platform-description-file> <target-directory>
 114  *
 115  * The <platform-description-file> is a file of this format:
 116  *     generate platforms <platform-ids-to-generate separate with ':'>
 117  *     platform version <platform-id1> files <.sym.txt files containing history data for given platform, separate with ':'>
 118  *     platform version <platform-id2> base <base-platform-id> files <.sym.txt files containing history data for given platform, separate with ':'>
 119  *
 120  * The content of platform "<base-platform-id>" is also automatically added to the content of
 121  * platform "<platform-id2>", unless explicitly excluded in "<platform-id2>"'s .sym.txt files.
 122  *
 123  * To create the .sym.txt files, first run the history Probe for all the previous platforms:
 124  *     <jdk-N>/bin/java build.tools.symbolgenerator.Probe <classes-for-N>
 125  *
 126  * Where <classes-for-N> is a name of a file into which the classes from the bootclasspath of <jdk-N>
 127  * will be written.
 128  *
 129  * Then create the .sym.txt files like this:
 130  *     java build.tools.symbolgenerator.CreateSymbols build-description <target-directory> <path-to-a-JDK-root> <include-list-file>
 131  *                                                    <platform-id1> <target-file-for-platform1> "<none>"
 132  *                                                    <platform-id2> <target-file-for-platform2> <diff-against-platform2>
 133  *                                                    <platform-id3> <target-file-for-platform3> <diff-against-platform3>
 134  *                                                    ...
 135  *
 136  * The <include-list-file> is a file that specifies classes that should be included/excluded.
 137  * Lines that start with '+' represent class or package that should be included, '-' class or package
 138  * that should be excluded. '/' should be used as package name delimiter, packages should end with '/'.
 139  * Several include list files may be specified, separated by File.pathSeparator.
 140  *
 141  * When <diff-against-platformN> is specified, the .sym.txt files for platform N will only contain
 142  * differences between platform N and the specified platform. The first platform (denoted F further)
 143  * that is specified should use literal value "<none>", to have all the APIs of the platform written to
 144  * the .sym.txt files. If there is an existing platform with full .sym.txt files in the repository,
 145  * that platform should be used as the first platform to avoid unnecessary changes to the .sym.txt
 146  * files. The <diff-against-platformN> for platform N should be determined as follows: if N < F, then
 147  * <diff-against-platformN> should be N + 1. If F < N, then <diff-against-platformN> should be N - 1.
 148  * If N is a custom/specialized sub-version of another platform N', then <diff-against-platformN> should be N'.
 149  *
 150  * To generate the .sym.txt files for OpenJDK 7 and 8:
 151  *     <jdk-7>/bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes
 152  *     <jdk-8>/bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes
 153  *     java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list
 154  *                                                    8 OpenJDK8.classes '<none>'
 155  *                                                    7 OpenJDK7.classes 8
 156  *
 157  * Note: the versions are expected to be a single character.
 158  */
 159 public class CreateSymbols {
 160 
 161     //<editor-fold defaultstate="collapsed" desc="ct.sym construction">
 162     /**Create sig files for ct.sym reading the classes description from the directory that contains
 163      * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
 164      */
 165     @SuppressWarnings("unchecked")
 166     public void createSymbols(String ctDescriptionFile, String ctSymLocation, CtSymKind ctSymKind) throws IOException {
 167         ClassList classes = load(Paths.get(ctDescriptionFile));
 168 
 169         splitHeaders(classes);
 170 
 171         for (ClassDescription classDescription : classes) {
 172             for (ClassHeaderDescription header : classDescription.header) {


 902         Map<String, String> package2Modules = buildPackage2Modules(jdkRoot);
 903         Map<String, List<ClassDescription>> module2Classes = new HashMap<>();
 904 
 905         for (ClassDescription clazz : classes) {
 906             String pack;
 907             int lastSlash = clazz.name.lastIndexOf('/');
 908             if (lastSlash != (-1)) {
 909                 pack = clazz.name.substring(0, lastSlash).replace('/', '.');
 910             } else {
 911                 pack = "";
 912             }
 913             String module = package2Modules.get(pack);
 914 
 915             if (module == null) {
 916                 module = "java.base";
 917 
 918                 OUTER: while (!pack.isEmpty()) {
 919                     for (Entry<String, String> p2M : package2Modules.entrySet()) {
 920                         if (p2M.getKey().startsWith(pack)) {
 921                             module = p2M.getValue();
 922                             break OUTER;
 923                         }
 924                     }
 925                     int dot = pack.lastIndexOf('.');
 926                     if (dot == (-1))
 927                         break;
 928                     pack = pack.substring(0, dot);
 929                 }
 930             }
 931             module2Classes.computeIfAbsent(module, m -> new ArrayList<>())
 932                     .add(clazz);
 933         }
 934 
 935         Path symbolsFile = descDest.resolve("symbols");
 936 
 937         Files.createDirectories(symbolsFile.getParent());
 938 
 939         try (Writer symbolsOut = Files.newBufferedWriter(symbolsFile)) {
 940             Map<VersionDescription, List<Path>> outputFiles = new LinkedHashMap<>();
 941 
 942             for (Entry<String, List<ClassDescription>> e : module2Classes.entrySet()) {
 943                 for (VersionDescription desc : versions) {
 944                     Path f = descDest.resolve(e.getKey() + "-" + desc.version + ".sym.txt");

 945                     try (Writer out = Files.newBufferedWriter(f)) {
 946                         for (ClassDescription clazz : e.getValue()) {
 947                             clazz.write(out, desc.primaryBaseline, desc.version);
 948                         }
 949                     }
 950                     outputFiles.computeIfAbsent(desc, d -> new ArrayList<>())
 951                                .add(f);
 952                 }
 953             }
 954             symbolsOut.append("generate platforms ")
 955                       .append(versions.stream()
 956                                       .map(v -> v.version)
 957                                       .collect(Collectors.joining(":")))
 958                       .append("\n");
 959             for (Entry<VersionDescription, List<Path>> versionFileEntry : outputFiles.entrySet()) {
 960                 symbolsOut.append("platform version ")
 961                           .append(versionFileEntry.getKey().version);
 962                 if (versionFileEntry.getKey().primaryBaseline != null) {
 963                     symbolsOut.append(" base ")
 964                               .append(versionFileEntry.getKey().primaryBaseline);
 965                 }
 966                 symbolsOut.append(" files ")
 967                           .append(versionFileEntry.getValue()
 968                                                   .stream()
 969                                                   .map(p -> p.getFileName().toString())
 970                                                   .sorted()
 971                                                   .collect(Collectors.joining(":")))
 972                           .append("\n");
 973             }
 974         }
 975     }
 976 
 977     //<editor-fold defaultstate="collapsed" desc="Class Reading">
 978     //non-final for tests:
 979     public static String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;";
 980     public static boolean ALLOW_NON_EXISTING_CLASSES = false;
 981 
 982     private void inspectClassFile(InputStream in, ClassList classes, ExcludeIncludeList excludesIncludes, String version) throws IOException, ConstantPoolException {
 983         ClassFile cf = ClassFile.read(in);
 984 
 985         if (!excludesIncludes.accepts(cf.getName())) {
 986             return ;
 987         }
 988 
 989         ClassHeaderDescription headerDesc = new ClassHeaderDescription();
 990 
 991         headerDesc.flags = cf.access_flags.flags;
 992 


< prev index next >