< prev index next >

src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java

Print this page




   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
  23  * questions.
  24  */
  25 
  26 package jdk.internal.module;
  27 
  28 import java.io.File;

  29 import java.io.PrintStream;

  30 import java.lang.module.Configuration;
  31 import java.lang.module.ModuleDescriptor;
  32 import java.lang.module.ModuleFinder;
  33 import java.lang.module.ModuleReference;
  34 import java.lang.module.ResolvedModule;
  35 import java.lang.reflect.Layer;
  36 import java.lang.reflect.Module;
  37 import java.net.URI;

  38 import java.nio.file.Path;
  39 import java.nio.file.Paths;
  40 import java.util.ArrayList;
  41 import java.util.Collections;
  42 import java.util.HashMap;
  43 import java.util.HashSet;
  44 import java.util.List;
  45 import java.util.Map;
  46 import java.util.Optional;
  47 import java.util.Set;
  48 import java.util.function.Function;

  49 
  50 import jdk.internal.loader.BootLoader;
  51 import jdk.internal.loader.BuiltinClassLoader;
  52 import jdk.internal.misc.SharedSecrets;
  53 import jdk.internal.perf.PerfCounter;

  54 
  55 /**
  56  * Initializes/boots the module system.
  57  *
  58  * The {@link #boot() boot} method is called early in the startup to initialize
  59  * the module system. In summary, the boot method creates a Configuration by
  60  * resolving a set of module names specified via the launcher (or equivalent)
  61  * -m and --add-modules options. The modules are located on a module path that
  62  * is constructed from the upgrade module path, system modules, and application
  63  * module path. The Configuration is instantiated as the boot Layer with each
  64  * module in the the configuration defined to one of the built-in class loaders.
  65  */
  66 
  67 public final class ModuleBootstrap {
  68     private ModuleBootstrap() { }
  69 
  70     private static final String JAVA_BASE = "java.base";
  71 
  72     private static final String JAVA_SE = "java.se";
  73 


 178                     break;
 179                 default :
 180                     roots.add(mod);
 181             }
 182         }
 183 
 184         // --limit-modules
 185         String propValue = getAndRemoveProperty("jdk.module.limitmods");
 186         if (propValue != null) {
 187             Set<String> mods = new HashSet<>();
 188             for (String mod: propValue.split(",")) {
 189                 mods.add(mod);
 190             }
 191             finder = limitFinder(finder, mods, roots);
 192         }
 193 
 194         // If there is no initial module specified then assume that the initial
 195         // module is the unnamed module of the application class loader. This
 196         // is implemented by resolving "java.se" and all (non-java.*) modules
 197         // that export an API. If "java.se" is not observable then all java.*
 198         // modules are resolved.


 199         if (mainModule == null || addAllDefaultModules) {
 200             boolean hasJava = false;
 201             if (systemModules.find(JAVA_SE).isPresent()) {
 202                 // java.se is a system module
 203                 if (finder == systemModules || finder.find(JAVA_SE).isPresent()) {
 204                     // java.se is observable
 205                     hasJava = true;
 206                     roots.add(JAVA_SE);
 207                 }
 208             }
 209 
 210             for (ModuleReference mref : systemModules.findAll()) {
 211                 String mn = mref.descriptor().name();
 212                 if (hasJava && mn.startsWith("java."))
 213                     continue;
 214 



 215                 // add as root if observable and exports at least one package
 216                 if ((finder == systemModules || finder.find(mn).isPresent())) {
 217                     ModuleDescriptor descriptor = mref.descriptor();
 218                     for (ModuleDescriptor.Exports e : descriptor.exports()) {
 219                         if (!e.isQualified()) {
 220                             roots.add(mn);
 221                             break;
 222                         }
 223                     }
 224                 }
 225             }
 226         }
 227 
 228         // If `--add-modules ALL-SYSTEM` is specified then all observable system
 229         // modules will be resolved.
 230         if (addAllSystemModules) {
 231             ModuleFinder f = finder;  // observable modules
 232             systemModules.findAll()
 233                 .stream()

 234                 .map(ModuleReference::descriptor)
 235                 .map(ModuleDescriptor::name)
 236                 .filter(mn -> f.find(mn).isPresent())  // observable
 237                 .forEach(mn -> roots.add(mn));
 238         }
 239 
 240         // If `--add-modules ALL-MODULE-PATH` is specified then all observable
 241         // modules on the application module path will be resolved.
 242         if (appModulePath != null && addAllApplicationModules) {
 243             ModuleFinder f = finder;  // observable modules
 244             appModulePath.findAll()
 245                 .stream()
 246                 .map(ModuleReference::descriptor)
 247                 .map(ModuleDescriptor::name)
 248                 .filter(mn -> f.find(mn).isPresent())  // observable
 249                 .forEach(mn -> roots.add(mn));
 250         }
 251 
 252         PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t2);
 253 


 260                 && (upgradeModulePath == null)
 261                 && (appModulePath == null)
 262                 && (patcher.isEmpty())) {
 263             needPostResolutionChecks = false;
 264         }
 265 
 266         PrintStream traceOutput = null;
 267         if (Boolean.getBoolean("jdk.launcher.traceResolver"))
 268             traceOutput = System.out;
 269 
 270         // run the resolver to create the configuration
 271         Configuration cf = SharedSecrets.getJavaLangModuleAccess()
 272                 .resolveRequiresAndUses(finder,
 273                                         roots,
 274                                         needPostResolutionChecks,
 275                                         traceOutput);
 276 
 277         // time to create configuration
 278         PerfCounters.resolveTime.addElapsedTimeFrom(t3);
 279 


 280 
 281         // mapping of modules to class loaders
 282         Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
 283 
 284         // check that all modules to be mapped to the boot loader will be
 285         // loaded from the runtime image
 286         if (needPostResolutionChecks) {
 287             for (ResolvedModule resolvedModule : cf.modules()) {
 288                 ModuleReference mref = resolvedModule.reference();
 289                 String name = mref.descriptor().name();
 290                 ClassLoader cl = clf.apply(name);
 291                 if (cl == null) {
 292 
 293                     if (upgradeModulePath != null
 294                             && upgradeModulePath.find(name).isPresent())
 295                         fail(name + ": cannot be loaded from upgrade module path");
 296 
 297                     if (!systemModules.find(name).isPresent())
 298                         fail(name + ": cannot be loaded from application module path");
 299                 }


 479 
 480     /**
 481      * Process the --add-exports and --add-opens options to export/open
 482      * additional packages specified on the command-line.
 483      */
 484     private static void addExtraExportsAndOpens(Layer bootLayer) {
 485 
 486         // --add-exports
 487         String prefix = "jdk.module.addexports.";
 488         Map<String, List<String>> extraExports = decode(prefix);
 489         if (!extraExports.isEmpty()) {
 490             addExtraExportsOrOpens(bootLayer, extraExports, false);
 491         }
 492 
 493         // --add-opens
 494         prefix = "jdk.module.addopens.";
 495         Map<String, List<String>> extraOpens = decode(prefix);
 496         if (!extraOpens.isEmpty()) {
 497             addExtraExportsOrOpens(bootLayer, extraOpens, true);
 498         }








































 499     }
 500 

 501     private static void addExtraExportsOrOpens(Layer bootLayer,
 502                                                Map<String, List<String>> map,
 503                                                boolean opens)
 504     {
 505         for (Map.Entry<String, List<String>> e : map.entrySet()) {
 506 
 507             // the key is $MODULE/$PACKAGE
 508             String key = e.getKey();
 509             String[] s = key.split("/");
 510             if (s.length != 2)
 511                 fail("Unable to parse: " + key);
 512 
 513             String mn = s[0];
 514             String pn = s[1];
 515             if (mn.isEmpty() || pn.isEmpty())
 516                 fail("Module and package name must be specified:" + key);
 517 
 518             // The exporting module is in the boot layer
 519             Module m;
 520             Optional<Module> om = bootLayer.findModule(mn);
 521             if (!om.isPresent()) {
 522                 warn("Unknown module: " + mn);
 523                 continue;
 524             }
 525 
 526             m = om.get();
 527 
 528             if (!m.getDescriptor().packages().contains(pn)) {
 529                 warn("package " + pn + " not in " + mn);
 530                 continue;
 531             }
 532 
 533             // the value is the set of modules to export to (by name)
 534             for (String name : e.getValue()) {
 535                 boolean allUnnamed = false;
 536                 Module other = null;


 568      * --patch-modules options that are encoded in system properties.
 569      *
 570      * @param prefix the system property prefix
 571      * @praam regex the regex for splitting the RHS of the option value
 572      */
 573     private static Map<String, List<String>> decode(String prefix,
 574                                                     String regex,
 575                                                     boolean allowDuplicates) {
 576         int index = 0;
 577         // the system property is removed after decoding
 578         String value = getAndRemoveProperty(prefix + index);
 579         if (value == null)
 580             return Collections.emptyMap();
 581 
 582         Map<String, List<String>> map = new HashMap<>();
 583 
 584         while (value != null) {
 585 
 586             int pos = value.indexOf('=');
 587             if (pos == -1)
 588                 fail("Unable to parse: " + value);
 589             if (pos == 0)
 590                 fail("Missing module name in: " + value);
 591 
 592             // key is <module> or <module>/<package>
 593             String key = value.substring(0, pos);
 594 
 595             String rhs = value.substring(pos+1);
 596             if (rhs.isEmpty())
 597                 fail("Unable to parse: " + value);
 598 
 599             // value is <module>(,<module>)* or <file>(<pathsep><file>)*
 600             if (!allowDuplicates && map.containsKey(key))
 601                 fail(key + " specified more than once");
 602             List<String> values = map.computeIfAbsent(key, k -> new ArrayList<>());
 603             for (String s : rhs.split(regex)) {
 604                 if (s.length() > 0) values.add(s);
 605             }
 606 
 607             index++;
 608             value = getAndRemoveProperty(prefix + index);
 609         }
 610 
 611         return map;
 612     }
 613 
 614     /**
 615      * Decodes the values of --add-reads, -add-exports or --add-opens
 616      * which use the "," to separate the RHS of the option value.
 617      */
 618     private static Map<String, List<String>> decode(String prefix) {
 619         return decode(prefix, ",", true);
 620     }
 621 
 622     /**
 623      * Gets and remove the named system property
 624      */
 625     private static String getAndRemoveProperty(String key) {
 626         return (String)System.getProperties().remove(key);
 627     }
 628 
 629     /**



























 630      * Throws a RuntimeException with the given message
 631      */
 632     static void fail(String m) {
 633         throw new RuntimeException(m);
 634     }
 635 
 636     static void warn(String m) {
 637         System.err.println("WARNING: " + m);
 638     }
 639 
 640     static class PerfCounters {
 641 
 642         static PerfCounter systemModulesTime
 643             = PerfCounter.newPerfCounter("jdk.module.bootstrap.systemModulesTime");
 644         static PerfCounter defineBaseTime
 645             = PerfCounter.newPerfCounter("jdk.module.bootstrap.defineBaseTime");
 646         static PerfCounter optionsAndRootsTime
 647             = PerfCounter.newPerfCounter("jdk.module.bootstrap.optionsAndRootsTime");
 648         static PerfCounter resolveTime
 649             = PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime");


   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
  23  * questions.
  24  */
  25 
  26 package jdk.internal.module;
  27 
  28 import java.io.File;
  29 import java.io.IOException;
  30 import java.io.PrintStream;
  31 import java.io.UncheckedIOException;
  32 import java.lang.module.Configuration;
  33 import java.lang.module.ModuleDescriptor;
  34 import java.lang.module.ModuleFinder;
  35 import java.lang.module.ModuleReference;
  36 import java.lang.module.ResolvedModule;
  37 import java.lang.reflect.Layer;
  38 import java.lang.reflect.Module;
  39 import java.net.URI;
  40 import java.nio.file.Files;
  41 import java.nio.file.Path;
  42 import java.nio.file.Paths;
  43 import java.util.ArrayList;
  44 import java.util.Collections;
  45 import java.util.HashMap;
  46 import java.util.HashSet;
  47 import java.util.List;
  48 import java.util.Map;
  49 import java.util.Optional;
  50 import java.util.Set;
  51 import java.util.function.Function;
  52 import java.util.stream.Stream;
  53 
  54 import jdk.internal.loader.BootLoader;
  55 import jdk.internal.loader.BuiltinClassLoader;
  56 import jdk.internal.misc.SharedSecrets;
  57 import jdk.internal.perf.PerfCounter;
  58 import jdk.internal.reflect.Reflection;
  59 
  60 /**
  61  * Initializes/boots the module system.
  62  *
  63  * The {@link #boot() boot} method is called early in the startup to initialize
  64  * the module system. In summary, the boot method creates a Configuration by
  65  * resolving a set of module names specified via the launcher (or equivalent)
  66  * -m and --add-modules options. The modules are located on a module path that
  67  * is constructed from the upgrade module path, system modules, and application
  68  * module path. The Configuration is instantiated as the boot Layer with each
  69  * module in the the configuration defined to one of the built-in class loaders.
  70  */
  71 
  72 public final class ModuleBootstrap {
  73     private ModuleBootstrap() { }
  74 
  75     private static final String JAVA_BASE = "java.base";
  76 
  77     private static final String JAVA_SE = "java.se";
  78 


 183                     break;
 184                 default :
 185                     roots.add(mod);
 186             }
 187         }
 188 
 189         // --limit-modules
 190         String propValue = getAndRemoveProperty("jdk.module.limitmods");
 191         if (propValue != null) {
 192             Set<String> mods = new HashSet<>();
 193             for (String mod: propValue.split(",")) {
 194                 mods.add(mod);
 195             }
 196             finder = limitFinder(finder, mods, roots);
 197         }
 198 
 199         // If there is no initial module specified then assume that the initial
 200         // module is the unnamed module of the application class loader. This
 201         // is implemented by resolving "java.se" and all (non-java.*) modules
 202         // that export an API. If "java.se" is not observable then all java.*
 203         // modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
 204         // bit set in their ModuleResolution attribute flags are excluded from
 205         // the default set of roots.
 206         if (mainModule == null || addAllDefaultModules) {
 207             boolean hasJava = false;
 208             if (systemModules.find(JAVA_SE).isPresent()) {
 209                 // java.se is a system module
 210                 if (finder == systemModules || finder.find(JAVA_SE).isPresent()) {
 211                     // java.se is observable
 212                     hasJava = true;
 213                     roots.add(JAVA_SE);
 214                 }
 215             }
 216 
 217             for (ModuleReference mref : systemModules.findAll()) {
 218                 String mn = mref.descriptor().name();
 219                 if (hasJava && mn.startsWith("java."))
 220                     continue;
 221 
 222                 if (ModuleResolution.doNotResolveByDefault(mref))
 223                     continue;
 224 
 225                 // add as root if observable and exports at least one package
 226                 if ((finder == systemModules || finder.find(mn).isPresent())) {
 227                     ModuleDescriptor descriptor = mref.descriptor();
 228                     for (ModuleDescriptor.Exports e : descriptor.exports()) {
 229                         if (!e.isQualified()) {
 230                             roots.add(mn);
 231                             break;
 232                         }
 233                     }
 234                 }
 235             }
 236         }
 237 
 238         // If `--add-modules ALL-SYSTEM` is specified then all observable system
 239         // modules will be resolved.
 240         if (addAllSystemModules) {
 241             ModuleFinder f = finder;  // observable modules
 242             systemModules.findAll()
 243                 .stream()
 244                 .filter(mref -> !ModuleResolution.doNotResolveByDefault(mref))
 245                 .map(ModuleReference::descriptor)
 246                 .map(ModuleDescriptor::name)
 247                 .filter(mn -> f.find(mn).isPresent())  // observable
 248                 .forEach(mn -> roots.add(mn));
 249         }
 250 
 251         // If `--add-modules ALL-MODULE-PATH` is specified then all observable
 252         // modules on the application module path will be resolved.
 253         if (appModulePath != null && addAllApplicationModules) {
 254             ModuleFinder f = finder;  // observable modules
 255             appModulePath.findAll()
 256                 .stream()
 257                 .map(ModuleReference::descriptor)
 258                 .map(ModuleDescriptor::name)
 259                 .filter(mn -> f.find(mn).isPresent())  // observable
 260                 .forEach(mn -> roots.add(mn));
 261         }
 262 
 263         PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t2);
 264 


 271                 && (upgradeModulePath == null)
 272                 && (appModulePath == null)
 273                 && (patcher.isEmpty())) {
 274             needPostResolutionChecks = false;
 275         }
 276 
 277         PrintStream traceOutput = null;
 278         if (Boolean.getBoolean("jdk.launcher.traceResolver"))
 279             traceOutput = System.out;
 280 
 281         // run the resolver to create the configuration
 282         Configuration cf = SharedSecrets.getJavaLangModuleAccess()
 283                 .resolveRequiresAndUses(finder,
 284                                         roots,
 285                                         needPostResolutionChecks,
 286                                         traceOutput);
 287 
 288         // time to create configuration
 289         PerfCounters.resolveTime.addElapsedTimeFrom(t3);
 290 
 291         // check module names and incubating status
 292         checkModuleNamesAndStatus(cf);
 293 
 294         // mapping of modules to class loaders
 295         Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
 296 
 297         // check that all modules to be mapped to the boot loader will be
 298         // loaded from the runtime image
 299         if (needPostResolutionChecks) {
 300             for (ResolvedModule resolvedModule : cf.modules()) {
 301                 ModuleReference mref = resolvedModule.reference();
 302                 String name = mref.descriptor().name();
 303                 ClassLoader cl = clf.apply(name);
 304                 if (cl == null) {
 305 
 306                     if (upgradeModulePath != null
 307                             && upgradeModulePath.find(name).isPresent())
 308                         fail(name + ": cannot be loaded from upgrade module path");
 309 
 310                     if (!systemModules.find(name).isPresent())
 311                         fail(name + ": cannot be loaded from application module path");
 312                 }


 492 
 493     /**
 494      * Process the --add-exports and --add-opens options to export/open
 495      * additional packages specified on the command-line.
 496      */
 497     private static void addExtraExportsAndOpens(Layer bootLayer) {
 498 
 499         // --add-exports
 500         String prefix = "jdk.module.addexports.";
 501         Map<String, List<String>> extraExports = decode(prefix);
 502         if (!extraExports.isEmpty()) {
 503             addExtraExportsOrOpens(bootLayer, extraExports, false);
 504         }
 505 
 506         // --add-opens
 507         prefix = "jdk.module.addopens.";
 508         Map<String, List<String>> extraOpens = decode(prefix);
 509         if (!extraOpens.isEmpty()) {
 510             addExtraExportsOrOpens(bootLayer, extraOpens, true);
 511         }
 512 
 513         // DEBUG_ADD_OPENS is for debugging purposes only
 514         String home = System.getProperty("java.home");
 515         Path file = Paths.get(home, "conf", "DEBUG_ADD_OPENS");
 516         if (Files.exists(file)) {
 517             warn(file + " detected; may break encapsulation");
 518             try (Stream<String> lines = Files.lines(file)) {
 519                 lines.map(line -> line.trim())
 520                     .filter(line -> (!line.isEmpty() && !line.startsWith("#")))
 521                     .forEach(line -> {
 522                         String[] s = line.split("/");
 523                         if (s.length != 2) {
 524                             fail("Unable to parse as <module>/<package>: " + line);
 525                         } else {
 526                             String mn = s[0];
 527                             String pkg = s[1];
 528                             openPackage(bootLayer, mn, pkg);
 529                         }
 530                     });
 531             } catch (IOException ioe) {
 532                 throw new UncheckedIOException(ioe);
 533             }
 534             Reflection.enableStackTraces();
 535         }
 536     }
 537 
 538     private static void openPackage(Layer bootLayer, String mn, String pkg) {
 539         if (mn.equals("ALL-RESOLVED") && pkg.equals("ALL-PACKAGES")) {
 540             bootLayer.modules().stream().forEach(m ->
 541                 m.getDescriptor().packages().forEach(pn -> openPackage(m, pn)));
 542         } else {
 543             bootLayer.findModule(mn)
 544                      .filter(m -> m.getDescriptor().packages().contains(pkg))
 545                      .ifPresent(m -> openPackage(m, pkg));
 546         }
 547     }
 548 
 549     private static void openPackage(Module m, String pn) {
 550         Modules.addOpensToAllUnnamed(m, pn);
 551         warn("Opened for deep reflection: " + m.getName()  + "/" + pn);
 552     }
 553 
 554 
 555     private static void addExtraExportsOrOpens(Layer bootLayer,
 556                                                Map<String, List<String>> map,
 557                                                boolean opens)
 558     {
 559         for (Map.Entry<String, List<String>> e : map.entrySet()) {
 560 
 561             // the key is $MODULE/$PACKAGE
 562             String key = e.getKey();
 563             String[] s = key.split("/");
 564             if (s.length != 2)
 565                 fail("Unable to parse as <module>/<package>: " + key);
 566 
 567             String mn = s[0];
 568             String pn = s[1];
 569             if (mn.isEmpty() || pn.isEmpty())
 570                 fail("Module and package name must be specified: " + key);
 571 
 572             // The exporting module is in the boot layer
 573             Module m;
 574             Optional<Module> om = bootLayer.findModule(mn);
 575             if (!om.isPresent()) {
 576                 warn("Unknown module: " + mn);
 577                 continue;
 578             }
 579 
 580             m = om.get();
 581 
 582             if (!m.getDescriptor().packages().contains(pn)) {
 583                 warn("package " + pn + " not in " + mn);
 584                 continue;
 585             }
 586 
 587             // the value is the set of modules to export to (by name)
 588             for (String name : e.getValue()) {
 589                 boolean allUnnamed = false;
 590                 Module other = null;


 622      * --patch-modules options that are encoded in system properties.
 623      *
 624      * @param prefix the system property prefix
 625      * @praam regex the regex for splitting the RHS of the option value
 626      */
 627     private static Map<String, List<String>> decode(String prefix,
 628                                                     String regex,
 629                                                     boolean allowDuplicates) {
 630         int index = 0;
 631         // the system property is removed after decoding
 632         String value = getAndRemoveProperty(prefix + index);
 633         if (value == null)
 634             return Collections.emptyMap();
 635 
 636         Map<String, List<String>> map = new HashMap<>();
 637 
 638         while (value != null) {
 639 
 640             int pos = value.indexOf('=');
 641             if (pos == -1)
 642                 fail("Unable to parse as <module>=<value>: " + value);
 643             if (pos == 0)
 644                 fail("Missing module name in: " + value);
 645 
 646             // key is <module> or <module>/<package>
 647             String key = value.substring(0, pos);
 648 
 649             String rhs = value.substring(pos+1);
 650             if (rhs.isEmpty())
 651                 fail("Unable to parse as <module>=<value>: " + value);
 652 
 653             // value is <module>(,<module>)* or <file>(<pathsep><file>)*
 654             if (!allowDuplicates && map.containsKey(key))
 655                 fail(key + " specified more than once");
 656             List<String> values = map.computeIfAbsent(key, k -> new ArrayList<>());
 657             for (String s : rhs.split(regex)) {
 658                 if (s.length() > 0) values.add(s);
 659             }
 660 
 661             index++;
 662             value = getAndRemoveProperty(prefix + index);
 663         }
 664 
 665         return map;
 666     }
 667 
 668     /**
 669      * Decodes the values of --add-reads, -add-exports or --add-opens
 670      * which use the "," to separate the RHS of the option value.
 671      */
 672     private static Map<String, List<String>> decode(String prefix) {
 673         return decode(prefix, ",", true);
 674     }
 675 
 676     /**
 677      * Gets and remove the named system property
 678      */
 679     private static String getAndRemoveProperty(String key) {
 680         return (String)System.getProperties().remove(key);
 681     }
 682 
 683     /**
 684      * Checks the names and resolution bit of each module in the configuration,
 685      * emitting warnings if needed.
 686      */
 687     private static void checkModuleNamesAndStatus(Configuration cf) {
 688         String incubating = null;
 689         for (ResolvedModule rm : cf.modules()) {
 690             ModuleReference mref = rm.reference();
 691             String mn = mref.descriptor().name();
 692 
 693             // emit warning if module name ends with a non-Java letter
 694             //if (!Checks.hasLegalModuleNameLastCharacter(mn))
 695             //    warn("Module name \"" + mn + "\" may soon be illegal");
 696 
 697             // emit warning if the WARN_INCUBATING module resolution bit set
 698             if (ModuleResolution.hasIncubatingWarning(mref)) {
 699                 if (incubating == null) {
 700                     incubating = mn;
 701                 } else {
 702                     incubating += ", " + mn;
 703                 }
 704             }
 705         }
 706         if (incubating != null)
 707             warn("using incubating module(s): " + incubating);
 708     }
 709 
 710     /**
 711      * Throws a RuntimeException with the given message
 712      */
 713     static void fail(String m) {
 714         throw new RuntimeException(m);
 715     }
 716 
 717     static void warn(String m) {
 718         System.err.println("WARNING: " + m);
 719     }
 720 
 721     static class PerfCounters {
 722 
 723         static PerfCounter systemModulesTime
 724             = PerfCounter.newPerfCounter("jdk.module.bootstrap.systemModulesTime");
 725         static PerfCounter defineBaseTime
 726             = PerfCounter.newPerfCounter("jdk.module.bootstrap.defineBaseTime");
 727         static PerfCounter optionsAndRootsTime
 728             = PerfCounter.newPerfCounter("jdk.module.bootstrap.optionsAndRootsTime");
 729         static PerfCounter resolveTime
 730             = PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime");
< prev index next >