src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java
changeset 58843 63994dedec49
parent 57939 e8ba7e4f4190
equal deleted inserted replaced
58842:6c255334120d 58843:63994dedec49
    34 import java.util.EnumSet;
    34 import java.util.EnumSet;
    35 import java.util.Map;
    35 import java.util.Map;
    36 import java.util.Set;
    36 import java.util.Set;
    37 import java.util.TreeMap;
    37 import java.util.TreeMap;
    38 import java.util.TreeSet;
    38 import java.util.TreeSet;
    39 import java.util.stream.Collectors;
       
    40 import java.util.stream.Stream;
    39 import java.util.stream.Stream;
    41 import jdk.internal.access.SharedSecrets;
    40 import jdk.internal.access.SharedSecrets;
    42 import jdk.internal.access.JavaLangInvokeAccess;
    41 import jdk.internal.access.JavaLangInvokeAccess;
    43 import jdk.tools.jlink.plugin.ResourcePoolEntry;
    42 import jdk.tools.jlink.plugin.ResourcePoolEntry;
    44 import jdk.tools.jlink.plugin.PluginException;
    43 import jdk.tools.jlink.plugin.PluginException;
    73     private static final String INVOKERS_HOLDER_INTERNAL_NAME = INVOKERS_HOLDER_NAME.replace('.', '/');
    72     private static final String INVOKERS_HOLDER_INTERNAL_NAME = INVOKERS_HOLDER_NAME.replace('.', '/');
    74 
    73 
    75     private static final JavaLangInvokeAccess JLIA
    74     private static final JavaLangInvokeAccess JLIA
    76             = SharedSecrets.getJavaLangInvokeAccess();
    75             = SharedSecrets.getJavaLangInvokeAccess();
    77 
    76 
    78     Set<String> speciesTypes = Set.of();
    77     private final TreeSet<String> speciesTypes = new TreeSet<>();
    79 
    78 
    80     Set<String> invokerTypes = Set.of();
    79     private final TreeSet<String> invokerTypes = new TreeSet<>();
    81 
    80 
    82     Set<String> callSiteTypes = Set.of();
    81     private final TreeSet<String> callSiteTypes = new TreeSet<>();
    83 
    82 
    84     Map<String, Set<String>> dmhMethods = Map.of();
    83     private final Map<String, Set<String>> dmhMethods = new TreeMap<>();
    85 
    84 
    86     String mainArgument;
    85     String mainArgument;
    87 
    86 
    88     public GenerateJLIClassesPlugin() {
    87     public GenerateJLIClassesPlugin() {
    89     }
    88     }
   185     @Override
   184     @Override
   186     public void configure(Map<String, String> config) {
   185     public void configure(Map<String, String> config) {
   187         mainArgument = config.get(NAME);
   186         mainArgument = config.get(NAME);
   188     }
   187     }
   189 
   188 
       
   189     private void addSpeciesType(String type) {
       
   190         speciesTypes.add(expandSignature(type));
       
   191     }
       
   192 
       
   193     private void addInvokerType(String methodType) {
       
   194         validateMethodType(methodType);
       
   195         invokerTypes.add(methodType);
       
   196     }
       
   197 
       
   198     private void addCallSiteType(String csType) {
       
   199         validateMethodType(csType);
       
   200         callSiteTypes.add(csType);
       
   201     }
       
   202 
   190     public void initialize(ResourcePool in) {
   203     public void initialize(ResourcePool in) {
   191         // Start with the default configuration
   204         // Start with the default configuration
   192         speciesTypes = defaultSpecies().stream()
   205         defaultSpecies().stream().forEach(this::addSpeciesType);
   193                 .map(type -> expandSignature(type))
   206 
   194                 .collect(Collectors.toSet());
   207         defaultInvokers().stream().forEach(this::validateMethodType);
   195 
   208 
   196         invokerTypes = defaultInvokers();
   209         defaultCallSiteTypes().stream().forEach(this::addCallSiteType);
   197         validateMethodTypes(invokerTypes);
   210 
   198 
   211         defaultDMHMethods().entrySet().stream().forEach(e -> {
   199         callSiteTypes = defaultCallSiteTypes();
   212             e.getValue().stream().forEach(type -> addDMHMethodType(e.getKey(), type));
   200 
   213         });
   201         dmhMethods = defaultDMHMethods();
       
   202         for (Set<String> dmhMethodTypes : dmhMethods.values()) {
       
   203             validateMethodTypes(dmhMethodTypes);
       
   204         }
       
   205 
   214 
   206         // Extend the default configuration with the contents in the supplied
   215         // Extend the default configuration with the contents in the supplied
   207         // input file - if none was supplied we look for the default file
   216         // input file - if none was supplied we look for the default file
   208         if (mainArgument == null || !mainArgument.startsWith("@")) {
   217         if (mainArgument == null || !mainArgument.startsWith("@")) {
   209             try (InputStream traceFile =
   218             try (InputStream traceFile =
   223             }
   232             }
   224         }
   233         }
   225     }
   234     }
   226 
   235 
   227     private void readTraceConfig(Stream<String> lines) {
   236     private void readTraceConfig(Stream<String> lines) {
   228         // Use TreeSet/TreeMap to keep things sorted in a deterministic
       
   229         // order to avoid scrambling the layout on small changes and to
       
   230         // ease finding methods in the generated code
       
   231         speciesTypes = new TreeSet<>(speciesTypes);
       
   232         invokerTypes = new TreeSet<>(invokerTypes);
       
   233         callSiteTypes = new TreeSet<>(callSiteTypes);
       
   234 
       
   235         TreeMap<String, Set<String>> newDMHMethods = new TreeMap<>();
       
   236         for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
       
   237             newDMHMethods.put(entry.getKey(), new TreeSet<>(entry.getValue()));
       
   238         }
       
   239         dmhMethods = newDMHMethods;
       
   240         lines.map(line -> line.split(" "))
   237         lines.map(line -> line.split(" "))
   241              .forEach(parts -> {
   238              .forEach(parts -> {
   242                 switch (parts[0]) {
   239                 switch (parts[0]) {
   243                     case "[SPECIES_RESOLVE]":
   240                     case "[SPECIES_RESOLVE]":
   244                         // Allow for new types of species data classes being resolved here
   241                         // Allow for new types of species data classes being resolved here
   245                         if (parts.length == 3 && parts[1].startsWith("java.lang.invoke.BoundMethodHandle$Species_")) {
   242                         if (parts.length == 3 && parts[1].startsWith("java.lang.invoke.BoundMethodHandle$Species_")) {
   246                             String species = parts[1].substring("java.lang.invoke.BoundMethodHandle$Species_".length());
   243                             String species = parts[1].substring("java.lang.invoke.BoundMethodHandle$Species_".length());
   247                             if (!"L".equals(species)) {
   244                             if (!"L".equals(species)) {
   248                                 speciesTypes.add(expandSignature(species));
   245                                 addSpeciesType(species);
   249                             }
   246                             }
   250                         }
   247                         }
   251                         break;
   248                         break;
   252                     case "[LF_RESOLVE]":
   249                     case "[LF_RESOLVE]":
   253                         String methodType = parts[3];
   250                         String methodType = parts[3];
   254                         validateMethodType(methodType);
       
   255                         if (parts[1].equals(INVOKERS_HOLDER_NAME)) {
   251                         if (parts[1].equals(INVOKERS_HOLDER_NAME)) {
   256                             if ("linkToTargetMethod".equals(parts[2]) ||
   252                             if ("linkToTargetMethod".equals(parts[2]) ||
   257                                     "linkToCallSite".equals(parts[2])) {
   253                                     "linkToCallSite".equals(parts[2])) {
   258                                 callSiteTypes.add(methodType);
   254                                 addCallSiteType(methodType);
   259                             } else {
   255                             } else {
   260                                 invokerTypes.add(methodType);
   256                                 addInvokerType(methodType);
   261                             }
   257                             }
   262                         } else if (parts[1].contains("DirectMethodHandle")) {
   258                         } else if (parts[1].contains("DirectMethodHandle")) {
   263                             String dmh = parts[2];
   259                             String dmh = parts[2];
   264                             // ignore getObject etc for now (generated
   260                             // ignore getObject etc for now (generated
   265                             // by default)
   261                             // by default)
   286     private Stream<String> fileLines(File file) {
   282     private Stream<String> fileLines(File file) {
   287         try {
   283         try {
   288             return Files.lines(file.toPath());
   284             return Files.lines(file.toPath());
   289         } catch (IOException io) {
   285         } catch (IOException io) {
   290             throw new PluginException("Couldn't read file");
   286             throw new PluginException("Couldn't read file");
   291         }
       
   292     }
       
   293 
       
   294     private void validateMethodTypes(Set<String> dmhMethodTypes) {
       
   295         for (String type : dmhMethodTypes) {
       
   296             validateMethodType(type);
       
   297         }
   287         }
   298     }
   288     }
   299 
   289 
   300     private void validateMethodType(String type) {
   290     private void validateMethodType(String type) {
   301         String[] typeParts = type.split("_");
   291         String[] typeParts = type.split("_");
   338 
   328 
   339         // Generate LambdaForm Holder classes
   329         // Generate LambdaForm Holder classes
   340         generateHolderClasses(out);
   330         generateHolderClasses(out);
   341 
   331 
   342         // Let it go
   332         // Let it go
   343         speciesTypes = null;
   333         speciesTypes.clear();
   344         invokerTypes = null;
   334         invokerTypes.clear();
   345         dmhMethods = null;
   335         callSiteTypes.clear();
       
   336         dmhMethods.clear();
   346 
   337 
   347         return out.build();
   338         return out.build();
   348     }
   339     }
   349 
   340 
   350     @SuppressWarnings("unchecked")
   341     @SuppressWarnings("unchecked")