39 import java.nio.file.Paths;
40 import java.util.Collections;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.Map;
44 import java.util.Optional;
45 import java.util.Set;
46 import java.util.function.Function;
47
48 import jdk.internal.loader.BootLoader;
49 import jdk.internal.loader.BuiltinClassLoader;
50 import jdk.internal.misc.SharedSecrets;
51 import jdk.internal.perf.PerfCounter;
52
53 /**
54 * Initializes/boots the module system.
55 *
56 * The {@link #boot() boot} method is called early in the startup to initialize
57 * the module system. In summary, the boot method creates a Configuration by
58 * resolving a set of module names specified via the launcher (or equivalent)
59 * -m and -addmods options. The modules are located on a module path that is
60 * constructed from the upgrade module path, system modules, and application
61 * module path. The Configuration is instantiated as the boot Layer with each
62 * module in the the configuration defined to one of the built-in class loaders.
63 */
64
65 public final class ModuleBootstrap {
66 private ModuleBootstrap() { }
67
68 private static final String JAVA_BASE = "java.base";
69
70 private static final String JAVA_SE = "java.se";
71
72 // the token for "all default modules"
73 private static final String ALL_DEFAULT = "ALL-DEFAULT";
74
75 // the token for "all unnamed modules"
76 private static final String ALL_UNNAMED = "ALL-UNNAMED";
77
78 // the token for "all system modules"
79 private static final String ALL_SYSTEM = "ALL-SYSTEM";
80
110 long t1 = System.nanoTime();
111
112 // Once we have the system modules then we define the base module to
113 // the VM. We do this here so that java.base is defined as early as
114 // possible and also that resources in the base module can be located
115 // for error messages that may happen from here on.
116 ModuleReference base = systemModules.find(JAVA_BASE).orElse(null);
117 if (base == null)
118 throw new InternalError(JAVA_BASE + " not found");
119 URI baseUri = base.location().orElse(null);
120 if (baseUri == null)
121 throw new InternalError(JAVA_BASE + " does not have a location");
122 BootLoader.loadModule(base);
123 Modules.defineModule(null, base.descriptor(), baseUri);
124
125 PerfCounters.defineBaseTime.addElapsedTimeFrom(t1);
126
127
128 long t2 = System.nanoTime();
129
130 // -upgrademodulepath option specified to launcher
131 ModuleFinder upgradeModulePath
132 = createModulePathFinder("jdk.upgrade.module.path");
133 if (upgradeModulePath != null)
134 systemModules = ModuleFinder.compose(upgradeModulePath, systemModules);
135
136 // -modulepath option specified to the launcher
137 ModuleFinder appModulePath = createModulePathFinder("jdk.module.path");
138
139 // The module finder: [-upgrademodulepath] system [-modulepath]
140 ModuleFinder finder = systemModules;
141 if (appModulePath != null)
142 finder = ModuleFinder.compose(finder, appModulePath);
143
144 // The root modules to resolve
145 Set<String> roots = new HashSet<>();
146
147 // launcher -m option to specify the main/initial module
148 String mainModule = System.getProperty("jdk.module.main");
149 if (mainModule != null)
150 roots.add(mainModule);
151
152 // additional module(s) specified by -addmods
153 boolean addAllDefaultModules = false;
154 boolean addAllSystemModules = false;
155 boolean addAllApplicationModules = false;
156 String propValue = System.getProperty("jdk.launcher.addmods");
157 if (propValue != null) {
158 for (String mod: propValue.split(",")) {
159 switch (mod) {
160 case ALL_DEFAULT:
161 addAllDefaultModules = true;
162 break;
163 case ALL_SYSTEM:
164 addAllSystemModules = true;
165 break;
166 case ALL_MODULE_PATH:
167 addAllApplicationModules = true;
168 break;
169 default :
170 roots.add(mod);
171 }
172 }
173 }
174
175 // -limitmods
176 propValue = System.getProperty("jdk.launcher.limitmods");
177 if (propValue != null) {
178 Set<String> mods = new HashSet<>();
179 for (String mod: propValue.split(",")) {
180 mods.add(mod);
181 }
182 finder = limitFinder(finder, mods, roots);
183 }
184
185 // If there is no initial module specified then assume that the initial
186 // module is the unnamed module of the application class loader. This
187 // is implemented by resolving "java.se" and all (non-java.*) modules
188 // that export an API. If "java.se" is not observable then all java.*
189 // modules are resolved.
190 if (mainModule == null || addAllDefaultModules) {
191 boolean hasJava = false;
192 if (systemModules.find(JAVA_SE).isPresent()) {
193 // java.se is a system module
194 if (finder == systemModules || finder.find(JAVA_SE).isPresent()) {
195 // java.se is observable
196 hasJava = true;
199 }
200
201 for (ModuleReference mref : systemModules.findAll()) {
202 String mn = mref.descriptor().name();
203 if (hasJava && mn.startsWith("java."))
204 continue;
205
206 // add as root if observable and exports at least one package
207 if ((finder == systemModules || finder.find(mn).isPresent())) {
208 ModuleDescriptor descriptor = mref.descriptor();
209 for (ModuleDescriptor.Exports e : descriptor.exports()) {
210 if (!e.isQualified()) {
211 roots.add(mn);
212 break;
213 }
214 }
215 }
216 }
217 }
218
219 // If `-addmods ALL-SYSTEM` is specified then all observable system
220 // modules will be resolved.
221 if (addAllSystemModules) {
222 ModuleFinder f = finder; // observable modules
223 systemModules.findAll()
224 .stream()
225 .map(ModuleReference::descriptor)
226 .map(ModuleDescriptor::name)
227 .filter(mn -> f.find(mn).isPresent()) // observable
228 .forEach(mn -> roots.add(mn));
229 }
230
231 // If `-addmods ALL-MODULE-PATH` is specified then all observable
232 // modules on the application module path will be resolved.
233 if (appModulePath != null && addAllApplicationModules) {
234 ModuleFinder f = finder; // observable modules
235 appModulePath.findAll()
236 .stream()
237 .map(ModuleReference::descriptor)
238 .map(ModuleDescriptor::name)
239 .filter(mn -> f.find(mn).isPresent()) // observable
240 .forEach(mn -> roots.add(mn));
241 }
242
243 PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t2);
244
245
246 long t3 = System.nanoTime();
247
248 // determine if post resolution checks are needed
249 boolean needPostResolutionChecks = true;
250 if (baseUri.getScheme().equals("jrt") // toLowerCase not needed here
251 && (upgradeModulePath == null)
252 && (appModulePath == null)
253 && (System.getProperty("jdk.launcher.patch.0") == null)) {
254 needPostResolutionChecks = false;
255 }
256
257 PrintStream traceOutput = null;
258 if (Boolean.getBoolean("jdk.launcher.traceResolver"))
259 traceOutput = System.out;
260
261 // run the resolver to create the configuration
262 Configuration cf = SharedSecrets.getJavaLangModuleAccess()
263 .resolveRequiresAndUses(finder,
264 roots,
265 needPostResolutionChecks,
266 traceOutput);
267
268 // time to create configuration
269 PerfCounters.resolveTime.addElapsedTimeFrom(t3);
270
271
272 // mapping of modules to class loaders
273 Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
300 PerfCounters.layerCreateTime.addElapsedTimeFrom(t4);
301
302
303 long t5 = System.nanoTime();
304
305 // define the module to its class loader, except java.base
306 for (ResolvedModule resolvedModule : cf.modules()) {
307 ModuleReference mref = resolvedModule.reference();
308 String name = mref.descriptor().name();
309 ClassLoader cl = clf.apply(name);
310 if (cl == null) {
311 if (!name.equals(JAVA_BASE)) BootLoader.loadModule(mref);
312 } else {
313 ((BuiltinClassLoader)cl).loadModule(mref);
314 }
315 }
316
317 PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
318
319
320 // -XaddReads and -XaddExports
321 addExtraReads(bootLayer);
322 addExtraExports(bootLayer);
323
324 // total time to initialize
325 PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
326
327 // remember the ModuleFinder
328 initialFinder = finder;
329
330 return bootLayer;
331 }
332
333 /**
334 * Returns a ModuleFinder that limits observability to the given root
335 * modules, their transitive dependences, plus a set of other modules.
336 */
337 private static ModuleFinder limitFinder(ModuleFinder finder,
338 Set<String> roots,
339 Set<String> otherMods)
340 {
377 * Creates a finder from the module path that is the value of the given
378 * system property.
379 */
380 private static ModuleFinder createModulePathFinder(String prop) {
381 String s = System.getProperty(prop);
382 if (s == null) {
383 return null;
384 } else {
385 String[] dirs = s.split(File.pathSeparator);
386 Path[] paths = new Path[dirs.length];
387 int i = 0;
388 for (String dir: dirs) {
389 paths[i++] = Paths.get(dir);
390 }
391 return ModuleFinder.of(paths);
392 }
393 }
394
395
396 /**
397 * Process the -XaddReads options to add any additional read edges that
398 * are specified on the command-line.
399 */
400 private static void addExtraReads(Layer bootLayer) {
401
402 // decode the command line options
403 Map<String, Set<String>> map = decode("jdk.launcher.addreads.");
404
405 for (Map.Entry<String, Set<String>> e : map.entrySet()) {
406
407 // the key is $MODULE
408 String mn = e.getKey();
409 Optional<Module> om = bootLayer.findModule(mn);
410 if (!om.isPresent())
411 fail("Unknown module: " + mn);
412 Module m = om.get();
413
414 // the value is the set of other modules (by name)
415 for (String name : e.getValue()) {
416
417 Module other;
418 if (ALL_UNNAMED.equals(name)) {
419 Modules.addReadsAllUnnamed(m);
420 } else {
421 om = bootLayer.findModule(name);
422 if (!om.isPresent())
423 fail("Unknown module: " + name);
424 other = om.get();
425 Modules.addReads(m, other);
426 }
427
428 }
429 }
430 }
431
432
433 /**
434 * Process the -XaddExports options to add any additional read edges that
435 * are specified on the command-line.
436 */
437 private static void addExtraExports(Layer bootLayer) {
438
439 // decode the command line options
440 Map<String, Set<String>> map = decode("jdk.launcher.addexports.");
441
442 for (Map.Entry<String, Set<String>> e : map.entrySet()) {
443
444 // the key is $MODULE/$PACKAGE
445 String key = e.getKey();
446 String[] s = key.split("/");
447 if (s.length != 2)
448 fail("Unable to parse: " + key);
449
450 String mn = s[0];
451 String pn = s[1];
452
453 // The exporting module is in the boot layer
454 Module m;
455 Optional<Module> om = bootLayer.findModule(mn);
456 if (!om.isPresent())
457 fail("Unknown module: " + mn);
458 m = om.get();
459
460 // the value is the set of modules to export to (by name)
466 } else {
467 om = bootLayer.findModule(name);
468 if (om.isPresent()) {
469 other = om.get();
470 } else {
471 fail("Unknown module: " + name);
472 }
473 }
474
475 if (allUnnamed) {
476 Modules.addExportsToAllUnnamed(m, pn);
477 } else {
478 Modules.addExports(m, pn, other);
479 }
480 }
481 }
482 }
483
484
485 /**
486 * Decodes the values of -XaddReads or -XaddExports options
487 *
488 * The format of the options is: $KEY=$MODULE(,$MODULE)*
489 */
490 private static Map<String, Set<String>> decode(String prefix) {
491 int index = 0;
492 String value = System.getProperty(prefix + index);
493 if (value == null)
494 return Collections.emptyMap();
495
496 Map<String, Set<String>> map = new HashMap<>();
497
498 while (value != null) {
499
500 int pos = value.indexOf('=');
501 if (pos == -1)
502 fail("Unable to parse: " + value);
503 if (pos == 0)
504 fail("Missing module name in: " + value);
505
506 // key is <module> or <module>/<package>
507 String key = value.substring(0, pos);
508
509 String rhs = value.substring(pos+1);
510 if (rhs.isEmpty())
511 fail("Unable to parse: " + value);
512
513
514 // value is <module>(,<module>)*
515 if (map.containsKey(key))
516 fail(key + " specified more than once");
517
518 Set<String> values = new HashSet<>();
519 map.put(key, values);
520 for (String s : rhs.split(",")) {
521 if (s.length() > 0) values.add(s);
522 }
523
524 index++;
525 value = System.getProperty(prefix + index);
526 }
527
528 return map;
529 }
530
531
532 /**
533 * Throws a RuntimeException with the given message
534 */
535 static void fail(String m) {
536 throw new RuntimeException(m);
537 }
538
539 static class PerfCounters {
540
541 static PerfCounter systemModulesTime
542 = PerfCounter.newPerfCounter("jdk.module.bootstrap.systemModulesTime");
543 static PerfCounter defineBaseTime
544 = PerfCounter.newPerfCounter("jdk.module.bootstrap.defineBaseTime");
545 static PerfCounter optionsAndRootsTime
546 = PerfCounter.newPerfCounter("jdk.module.bootstrap.optionsAndRootsTime");
547 static PerfCounter resolveTime
548 = PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime");
549 static PerfCounter layerCreateTime
550 = PerfCounter.newPerfCounter("jdk.module.bootstrap.layerCreateTime");
|
39 import java.nio.file.Paths;
40 import java.util.Collections;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.Map;
44 import java.util.Optional;
45 import java.util.Set;
46 import java.util.function.Function;
47
48 import jdk.internal.loader.BootLoader;
49 import jdk.internal.loader.BuiltinClassLoader;
50 import jdk.internal.misc.SharedSecrets;
51 import jdk.internal.perf.PerfCounter;
52
53 /**
54 * Initializes/boots the module system.
55 *
56 * The {@link #boot() boot} method is called early in the startup to initialize
57 * the module system. In summary, the boot method creates a Configuration by
58 * resolving a set of module names specified via the launcher (or equivalent)
59 * -m and --add-modules options. The modules are located on a module path that
60 * is constructed from the upgrade module path, system modules, and application
61 * module path. The Configuration is instantiated as the boot Layer with each
62 * module in the the configuration defined to one of the built-in class loaders.
63 */
64
65 public final class ModuleBootstrap {
66 private ModuleBootstrap() { }
67
68 private static final String JAVA_BASE = "java.base";
69
70 private static final String JAVA_SE = "java.se";
71
72 // the token for "all default modules"
73 private static final String ALL_DEFAULT = "ALL-DEFAULT";
74
75 // the token for "all unnamed modules"
76 private static final String ALL_UNNAMED = "ALL-UNNAMED";
77
78 // the token for "all system modules"
79 private static final String ALL_SYSTEM = "ALL-SYSTEM";
80
110 long t1 = System.nanoTime();
111
112 // Once we have the system modules then we define the base module to
113 // the VM. We do this here so that java.base is defined as early as
114 // possible and also that resources in the base module can be located
115 // for error messages that may happen from here on.
116 ModuleReference base = systemModules.find(JAVA_BASE).orElse(null);
117 if (base == null)
118 throw new InternalError(JAVA_BASE + " not found");
119 URI baseUri = base.location().orElse(null);
120 if (baseUri == null)
121 throw new InternalError(JAVA_BASE + " does not have a location");
122 BootLoader.loadModule(base);
123 Modules.defineModule(null, base.descriptor(), baseUri);
124
125 PerfCounters.defineBaseTime.addElapsedTimeFrom(t1);
126
127
128 long t2 = System.nanoTime();
129
130 // --upgrade-module-path option specified to launcher
131 ModuleFinder upgradeModulePath
132 = createModulePathFinder("jdk.module.upgrade.path");
133 if (upgradeModulePath != null)
134 systemModules = ModuleFinder.compose(upgradeModulePath, systemModules);
135
136 // --module-path option specified to the launcher
137 ModuleFinder appModulePath = createModulePathFinder("jdk.module.path");
138
139 // The module finder: [--upgrade-module-path] system [--module-path]
140 ModuleFinder finder = systemModules;
141 if (appModulePath != null)
142 finder = ModuleFinder.compose(finder, appModulePath);
143
144 // The root modules to resolve
145 Set<String> roots = new HashSet<>();
146
147 // launcher -m option to specify the main/initial module
148 String mainModule = System.getProperty("jdk.module.main");
149 if (mainModule != null)
150 roots.add(mainModule);
151
152 // additional module(s) specified by --add-modules
153 boolean addAllDefaultModules = false;
154 boolean addAllSystemModules = false;
155 boolean addAllApplicationModules = false;
156 String propValue = getAndRemoveProperty("jdk.module.addmods");
157 if (propValue != null) {
158 for (String mod: propValue.split(",")) {
159 switch (mod) {
160 case ALL_DEFAULT:
161 addAllDefaultModules = true;
162 break;
163 case ALL_SYSTEM:
164 addAllSystemModules = true;
165 break;
166 case ALL_MODULE_PATH:
167 addAllApplicationModules = true;
168 break;
169 default :
170 roots.add(mod);
171 }
172 }
173 }
174
175 // --limit-modules
176 propValue = getAndRemoveProperty("jdk.module.limitmods");
177 if (propValue != null) {
178 Set<String> mods = new HashSet<>();
179 for (String mod: propValue.split(",")) {
180 mods.add(mod);
181 }
182 finder = limitFinder(finder, mods, roots);
183 }
184
185 // If there is no initial module specified then assume that the initial
186 // module is the unnamed module of the application class loader. This
187 // is implemented by resolving "java.se" and all (non-java.*) modules
188 // that export an API. If "java.se" is not observable then all java.*
189 // modules are resolved.
190 if (mainModule == null || addAllDefaultModules) {
191 boolean hasJava = false;
192 if (systemModules.find(JAVA_SE).isPresent()) {
193 // java.se is a system module
194 if (finder == systemModules || finder.find(JAVA_SE).isPresent()) {
195 // java.se is observable
196 hasJava = true;
199 }
200
201 for (ModuleReference mref : systemModules.findAll()) {
202 String mn = mref.descriptor().name();
203 if (hasJava && mn.startsWith("java."))
204 continue;
205
206 // add as root if observable and exports at least one package
207 if ((finder == systemModules || finder.find(mn).isPresent())) {
208 ModuleDescriptor descriptor = mref.descriptor();
209 for (ModuleDescriptor.Exports e : descriptor.exports()) {
210 if (!e.isQualified()) {
211 roots.add(mn);
212 break;
213 }
214 }
215 }
216 }
217 }
218
219 // If `--add-modules ALL-SYSTEM` is specified then all observable system
220 // modules will be resolved.
221 if (addAllSystemModules) {
222 ModuleFinder f = finder; // observable modules
223 systemModules.findAll()
224 .stream()
225 .map(ModuleReference::descriptor)
226 .map(ModuleDescriptor::name)
227 .filter(mn -> f.find(mn).isPresent()) // observable
228 .forEach(mn -> roots.add(mn));
229 }
230
231 // If `--add-modules ALL-MODULE-PATH` is specified then all observable
232 // modules on the application module path will be resolved.
233 if (appModulePath != null && addAllApplicationModules) {
234 ModuleFinder f = finder; // observable modules
235 appModulePath.findAll()
236 .stream()
237 .map(ModuleReference::descriptor)
238 .map(ModuleDescriptor::name)
239 .filter(mn -> f.find(mn).isPresent()) // observable
240 .forEach(mn -> roots.add(mn));
241 }
242
243 PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t2);
244
245
246 long t3 = System.nanoTime();
247
248 // determine if post resolution checks are needed
249 boolean needPostResolutionChecks = true;
250 if (baseUri.getScheme().equals("jrt") // toLowerCase not needed here
251 && (upgradeModulePath == null)
252 && (appModulePath == null)
253 && (!ModulePatcher.isBootLayerPatched())) {
254 needPostResolutionChecks = false;
255 }
256
257 PrintStream traceOutput = null;
258 if (Boolean.getBoolean("jdk.launcher.traceResolver"))
259 traceOutput = System.out;
260
261 // run the resolver to create the configuration
262 Configuration cf = SharedSecrets.getJavaLangModuleAccess()
263 .resolveRequiresAndUses(finder,
264 roots,
265 needPostResolutionChecks,
266 traceOutput);
267
268 // time to create configuration
269 PerfCounters.resolveTime.addElapsedTimeFrom(t3);
270
271
272 // mapping of modules to class loaders
273 Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
300 PerfCounters.layerCreateTime.addElapsedTimeFrom(t4);
301
302
303 long t5 = System.nanoTime();
304
305 // define the module to its class loader, except java.base
306 for (ResolvedModule resolvedModule : cf.modules()) {
307 ModuleReference mref = resolvedModule.reference();
308 String name = mref.descriptor().name();
309 ClassLoader cl = clf.apply(name);
310 if (cl == null) {
311 if (!name.equals(JAVA_BASE)) BootLoader.loadModule(mref);
312 } else {
313 ((BuiltinClassLoader)cl).loadModule(mref);
314 }
315 }
316
317 PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
318
319
320 // --add-reads and --add-exports
321 addExtraReads(bootLayer);
322 addExtraExports(bootLayer);
323
324 // total time to initialize
325 PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
326
327 // remember the ModuleFinder
328 initialFinder = finder;
329
330 return bootLayer;
331 }
332
333 /**
334 * Returns a ModuleFinder that limits observability to the given root
335 * modules, their transitive dependences, plus a set of other modules.
336 */
337 private static ModuleFinder limitFinder(ModuleFinder finder,
338 Set<String> roots,
339 Set<String> otherMods)
340 {
377 * Creates a finder from the module path that is the value of the given
378 * system property.
379 */
380 private static ModuleFinder createModulePathFinder(String prop) {
381 String s = System.getProperty(prop);
382 if (s == null) {
383 return null;
384 } else {
385 String[] dirs = s.split(File.pathSeparator);
386 Path[] paths = new Path[dirs.length];
387 int i = 0;
388 for (String dir: dirs) {
389 paths[i++] = Paths.get(dir);
390 }
391 return ModuleFinder.of(paths);
392 }
393 }
394
395
396 /**
397 * Process the --add-reads options to add any additional read edges that
398 * are specified on the command-line.
399 */
400 private static void addExtraReads(Layer bootLayer) {
401
402 // decode the command line options
403 Map<String, Set<String>> map = decode("jdk.module.addreads.");
404
405 for (Map.Entry<String, Set<String>> e : map.entrySet()) {
406
407 // the key is $MODULE
408 String mn = e.getKey();
409 Optional<Module> om = bootLayer.findModule(mn);
410 if (!om.isPresent())
411 fail("Unknown module: " + mn);
412 Module m = om.get();
413
414 // the value is the set of other modules (by name)
415 for (String name : e.getValue()) {
416
417 Module other;
418 if (ALL_UNNAMED.equals(name)) {
419 Modules.addReadsAllUnnamed(m);
420 } else {
421 om = bootLayer.findModule(name);
422 if (!om.isPresent())
423 fail("Unknown module: " + name);
424 other = om.get();
425 Modules.addReads(m, other);
426 }
427
428 }
429 }
430 }
431
432
433 /**
434 * Process the --add-exports options to add any additional read edges that
435 * are specified on the command-line.
436 */
437 private static void addExtraExports(Layer bootLayer) {
438
439 // decode the command line options
440 Map<String, Set<String>> map = decode("jdk.module.addexports.");
441
442 for (Map.Entry<String, Set<String>> e : map.entrySet()) {
443
444 // the key is $MODULE/$PACKAGE
445 String key = e.getKey();
446 String[] s = key.split("/");
447 if (s.length != 2)
448 fail("Unable to parse: " + key);
449
450 String mn = s[0];
451 String pn = s[1];
452
453 // The exporting module is in the boot layer
454 Module m;
455 Optional<Module> om = bootLayer.findModule(mn);
456 if (!om.isPresent())
457 fail("Unknown module: " + mn);
458 m = om.get();
459
460 // the value is the set of modules to export to (by name)
466 } else {
467 om = bootLayer.findModule(name);
468 if (om.isPresent()) {
469 other = om.get();
470 } else {
471 fail("Unknown module: " + name);
472 }
473 }
474
475 if (allUnnamed) {
476 Modules.addExportsToAllUnnamed(m, pn);
477 } else {
478 Modules.addExports(m, pn, other);
479 }
480 }
481 }
482 }
483
484
485 /**
486 * Decodes the values of --add-reads or --add-exports options
487 *
488 * The format of the options is: $KEY=$MODULE(,$MODULE)*
489 */
490 private static Map<String, Set<String>> decode(String prefix) {
491 int index = 0;
492 // the system property is removed after decoding
493 String value = getAndRemoveProperty(prefix + index);
494 if (value == null)
495 return Collections.emptyMap();
496
497 Map<String, Set<String>> map = new HashMap<>();
498
499 while (value != null) {
500
501 int pos = value.indexOf('=');
502 if (pos == -1)
503 fail("Unable to parse: " + value);
504 if (pos == 0)
505 fail("Missing module name in: " + value);
506
507 // key is <module> or <module>/<package>
508 String key = value.substring(0, pos);
509
510 String rhs = value.substring(pos+1);
511 if (rhs.isEmpty())
512 fail("Unable to parse: " + value);
513
514
515 // value is <module>(,<module>)*
516 if (map.containsKey(key))
517 fail(key + " specified more than once");
518
519 Set<String> values = new HashSet<>();
520 map.put(key, values);
521 for (String s : rhs.split(",")) {
522 if (s.length() > 0) values.add(s);
523 }
524
525 index++;
526 value = getAndRemoveProperty(prefix + index);
527 }
528
529 return map;
530 }
531
532 /**
533 * Gets and remove the named system property
534 */
535 private static String getAndRemoveProperty(String key) {
536 return (String)System.getProperties().remove(key);
537 }
538
539 /**
540 * Throws a RuntimeException with the given message
541 */
542 static void fail(String m) {
543 throw new RuntimeException(m);
544 }
545
546 static class PerfCounters {
547
548 static PerfCounter systemModulesTime
549 = PerfCounter.newPerfCounter("jdk.module.bootstrap.systemModulesTime");
550 static PerfCounter defineBaseTime
551 = PerfCounter.newPerfCounter("jdk.module.bootstrap.defineBaseTime");
552 static PerfCounter optionsAndRootsTime
553 = PerfCounter.newPerfCounter("jdk.module.bootstrap.optionsAndRootsTime");
554 static PerfCounter resolveTime
555 = PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime");
556 static PerfCounter layerCreateTime
557 = PerfCounter.newPerfCounter("jdk.module.bootstrap.layerCreateTime");
|