8237484: Improve module system bootstrap

Reviewed-by: alanb
This commit is contained in:
Claes Redestad 2020-02-07 10:23:35 +01:00
parent 9c8f05279c
commit 38f0c08ee0
2 changed files with 75 additions and 62 deletions

View file

@ -132,7 +132,7 @@ public final class Module implements AnnotatedElement {
Version version = descriptor.version().orElse(null); Version version = descriptor.version().orElse(null);
String vs = Objects.toString(version, null); String vs = Objects.toString(version, null);
String loc = Objects.toString(uri, null); String loc = Objects.toString(uri, null);
String[] packages = descriptor.packages().toArray(new String[0]); Object[] packages = descriptor.packages().toArray();
defineModule0(this, isOpen, vs, loc, packages); defineModule0(this, isOpen, vs, loc, packages);
} }
@ -1075,35 +1075,49 @@ public final class Module implements AnnotatedElement {
{ {
boolean isBootLayer = (ModuleLayer.boot() == null); boolean isBootLayer = (ModuleLayer.boot() == null);
int cap = (int)(cf.modules().size() / 0.75f + 1.0f); int numModules = cf.modules().size();
int cap = (int)(numModules / 0.75f + 1.0f);
Map<String, Module> nameToModule = new HashMap<>(cap); Map<String, Module> nameToModule = new HashMap<>(cap);
Map<String, ClassLoader> nameToLoader = new HashMap<>(cap);
Set<ClassLoader> loaders = new HashSet<>(); // to avoid repeated lookups and reduce iteration overhead, we create
// arrays holding correlated information about each module.
ResolvedModule[] resolvedModules = new ResolvedModule[numModules];
Module[] modules = new Module[numModules];
ClassLoader[] classLoaders = new ClassLoader[numModules];
resolvedModules = cf.modules().toArray(resolvedModules);
// record that we want to bind the layer to non-boot and non-platform
// module loaders as a final step
HashSet<ClassLoader> toBindLoaders = new HashSet<>(4);
boolean hasPlatformModules = false; boolean hasPlatformModules = false;
// map each module to a class loader // map each module to a class loader
for (ResolvedModule resolvedModule : cf.modules()) { ClassLoader pcl = ClassLoaders.platformClassLoader();
String name = resolvedModule.name();
for (int index = 0; index < numModules; index++) {
String name = resolvedModules[index].name();
ClassLoader loader = clf.apply(name); ClassLoader loader = clf.apply(name);
nameToLoader.put(name, loader);
if (loader == null || loader == ClassLoaders.platformClassLoader()) { if (loader == null || loader == pcl) {
if (!(clf instanceof ModuleLoaderMap.Mapper)) { if (!(clf instanceof ModuleLoaderMap.Mapper)) {
throw new IllegalArgumentException("loader can't be 'null'" throw new IllegalArgumentException("loader can't be 'null'"
+ " or the platform class loader"); + " or the platform class loader");
} }
hasPlatformModules = true; hasPlatformModules = true;
} else { } else {
loaders.add(loader); toBindLoaders.add(loader);
} }
classLoaders[index] = loader;
} }
// define each module in the configuration to the VM // define each module in the configuration to the VM
for (ResolvedModule resolvedModule : cf.modules()) { for (int index = 0; index < numModules; index++) {
ModuleReference mref = resolvedModule.reference(); ModuleReference mref = resolvedModules[index].reference();
ModuleDescriptor descriptor = mref.descriptor(); ModuleDescriptor descriptor = mref.descriptor();
String name = descriptor.name(); String name = descriptor.name();
ClassLoader loader = nameToLoader.get(name); ClassLoader loader = classLoaders[index];
Module m; Module m;
if (loader == null && name.equals("java.base")) { if (loader == null && name.equals("java.base")) {
// java.base is already defined to the VM // java.base is already defined to the VM
@ -1113,16 +1127,15 @@ public final class Module implements AnnotatedElement {
m = new Module(layer, loader, descriptor, uri); m = new Module(layer, loader, descriptor, uri);
} }
nameToModule.put(name, m); nameToModule.put(name, m);
modules[index] = m;
} }
// setup readability and exports/opens // setup readability and exports/opens
for (ResolvedModule resolvedModule : cf.modules()) { for (int index = 0; index < numModules; index++) {
ResolvedModule resolvedModule = resolvedModules[index];
ModuleReference mref = resolvedModule.reference(); ModuleReference mref = resolvedModule.reference();
ModuleDescriptor descriptor = mref.descriptor(); ModuleDescriptor descriptor = mref.descriptor();
Module m = modules[index];
String mn = descriptor.name();
Module m = nameToModule.get(mn);
assert m != null;
// reads // reads
Set<Module> reads = new HashSet<>(); Set<Module> reads = new HashSet<>();
@ -1174,16 +1187,15 @@ public final class Module implements AnnotatedElement {
// if there are modules defined to the boot or platform class loaders // if there are modules defined to the boot or platform class loaders
// then register the modules in the class loader's services catalog // then register the modules in the class loader's services catalog
if (hasPlatformModules) { if (hasPlatformModules) {
ClassLoader pcl = ClassLoaders.platformClassLoader();
ServicesCatalog bootCatalog = BootLoader.getServicesCatalog(); ServicesCatalog bootCatalog = BootLoader.getServicesCatalog();
ServicesCatalog pclCatalog = ServicesCatalog.getServicesCatalog(pcl); ServicesCatalog pclCatalog = ServicesCatalog.getServicesCatalog(pcl);
for (ResolvedModule resolvedModule : cf.modules()) { for (int index = 0; index < numModules; index++) {
ResolvedModule resolvedModule = resolvedModules[index];
ModuleReference mref = resolvedModule.reference(); ModuleReference mref = resolvedModule.reference();
ModuleDescriptor descriptor = mref.descriptor(); ModuleDescriptor descriptor = mref.descriptor();
if (!descriptor.provides().isEmpty()) { if (!descriptor.provides().isEmpty()) {
String name = descriptor.name(); Module m = modules[index];
Module m = nameToModule.get(name); ClassLoader loader = classLoaders[index];
ClassLoader loader = nameToLoader.get(name);
if (loader == null) { if (loader == null) {
bootCatalog.register(m); bootCatalog.register(m);
} else if (loader == pcl) { } else if (loader == pcl) {
@ -1194,7 +1206,7 @@ public final class Module implements AnnotatedElement {
} }
// record that there is a layer with modules defined to the class loader // record that there is a layer with modules defined to the class loader
for (ClassLoader loader : loaders) { for (ClassLoader loader : toBindLoaders) {
layer.bindToLoader(loader); layer.bindToLoader(loader);
} }
@ -1623,7 +1635,7 @@ public final class Module implements AnnotatedElement {
boolean isOpen, boolean isOpen,
String version, String version,
String location, String location,
String[] pns); Object[] pns);
// JVM_AddReadsModule // JVM_AddReadsModule
private static native void addReads0(Module from, Module to); private static native void addReads0(Module from, Module to);

View file

@ -140,9 +140,9 @@ public final class ModuleBootstrap {
*/ */
public static ModuleLayer boot() throws Exception { public static ModuleLayer boot() throws Exception {
// Step 0: Command line options Counters.start();
long t0 = System.nanoTime(); // Step 0: Command line options
ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path"); ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path");
ModuleFinder appModulePath = finderFor("jdk.module.path"); ModuleFinder appModulePath = finderFor("jdk.module.path");
@ -157,6 +157,7 @@ public final class ModuleBootstrap {
if (trace != null && Boolean.parseBoolean(trace)) if (trace != null && Boolean.parseBoolean(trace))
traceOutput = System.out; traceOutput = System.out;
Counters.add("jdk.module.boot.0.commandLineTime");
// Step 1: The observable system modules, either all system modules // Step 1: The observable system modules, either all system modules
// or the system modules pre-generated for the initial module (the // or the system modules pre-generated for the initial module (the
@ -164,8 +165,6 @@ public final class ModuleBootstrap {
// are pre-generated for the initial module then resolution can be // are pre-generated for the initial module then resolution can be
// skipped. // skipped.
long t1 = System.nanoTime();
SystemModules systemModules = null; SystemModules systemModules = null;
ModuleFinder systemModuleFinder; ModuleFinder systemModuleFinder;
@ -215,16 +214,13 @@ public final class ModuleBootstrap {
archivedModuleGraph = null; archivedModuleGraph = null;
} }
Counters.add("jdk.module.boot.1.systemModulesTime", t1); Counters.add("jdk.module.boot.1.systemModulesTime");
// Step 2: Define and load java.base. This patches all classes loaded // Step 2: Define and load java.base. This patches all classes loaded
// to date so that they are members of java.base. Once java.base is // to date so that they are members of java.base. Once java.base is
// loaded then resources in java.base are available for error messages // loaded then resources in java.base are available for error messages
// needed from here on. // needed from here on.
long t2 = System.nanoTime();
ModuleReference base = systemModuleFinder.find(JAVA_BASE).orElse(null); ModuleReference base = systemModuleFinder.find(JAVA_BASE).orElse(null);
if (base == null) if (base == null)
throw new InternalError(JAVA_BASE + " not found"); throw new InternalError(JAVA_BASE + " not found");
@ -234,9 +230,6 @@ public final class ModuleBootstrap {
BootLoader.loadModule(base); BootLoader.loadModule(base);
Modules.defineModule(null, base.descriptor(), baseUri); Modules.defineModule(null, base.descriptor(), baseUri);
Counters.add("jdk.module.boot.2.defineBaseTime", t2);
// Step 2a: Scan all modules when --validate-modules specified // Step 2a: Scan all modules when --validate-modules specified
if (getAndRemoveProperty("jdk.module.validation") != null) { if (getAndRemoveProperty("jdk.module.validation") != null) {
@ -246,12 +239,11 @@ public final class ModuleBootstrap {
} }
} }
Counters.add("jdk.module.boot.2.defineBaseTime");
// Step 3: If resolution is needed then create the module finder and // Step 3: If resolution is needed then create the module finder and
// the set of root modules to resolve. // the set of root modules to resolve.
long t3 = System.nanoTime();
ModuleFinder savedModuleFinder = null; ModuleFinder savedModuleFinder = null;
ModuleFinder finder; ModuleFinder finder;
Set<String> roots; Set<String> roots;
@ -341,15 +333,13 @@ public final class ModuleBootstrap {
roots = null; roots = null;
} }
Counters.add("jdk.module.boot.3.optionsAndRootsTime", t3); Counters.add("jdk.module.boot.3.optionsAndRootsTime");
// Step 4: Resolve the root modules, with service binding, to create // Step 4: Resolve the root modules, with service binding, to create
// the configuration for the boot layer. If resolution is not needed // the configuration for the boot layer. If resolution is not needed
// then create the configuration for the boot layer from the // then create the configuration for the boot layer from the
// readability graph created at link time. // readability graph created at link time.
long t4 = System.nanoTime();
Configuration cf; Configuration cf;
if (needResolution) { if (needResolution) {
cf = Modules.newBootLayerConfiguration(finder, roots, traceOutput); cf = Modules.newBootLayerConfiguration(finder, roots, traceOutput);
@ -370,8 +360,7 @@ public final class ModuleBootstrap {
.forEach(mn -> warnUnknownModule(PATCH_MODULE, mn)); .forEach(mn -> warnUnknownModule(PATCH_MODULE, mn));
} }
Counters.add("jdk.module.boot.4.resolveTime", t4); Counters.add("jdk.module.boot.4.resolveTime");
// Step 5: Map the modules in the configuration to class loaders. // Step 5: Map the modules in the configuration to class loaders.
// The static configuration provides the mapping of standard and JDK // The static configuration provides the mapping of standard and JDK
@ -380,8 +369,6 @@ public final class ModuleBootstrap {
// application module path) are defined to the application class // application module path) are defined to the application class
// loader. // loader.
long t5 = System.nanoTime();
// mapping of modules to class loaders // mapping of modules to class loaders
Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf); Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
@ -409,16 +396,12 @@ public final class ModuleBootstrap {
// load/register the modules with the built-in class loaders // load/register the modules with the built-in class loaders
loadModules(cf, clf); loadModules(cf, clf);
Counters.add("jdk.module.boot.5.loadModulesTime");
Counters.add("jdk.module.boot.5.loadModulesTime", t5);
// Step 6: Define all modules to the VM // Step 6: Define all modules to the VM
long t6 = System.nanoTime();
ModuleLayer bootLayer = ModuleLayer.empty().defineModules(cf, clf); ModuleLayer bootLayer = ModuleLayer.empty().defineModules(cf, clf);
Counters.add("jdk.module.boot.6.layerCreateTime", t6); Counters.add("jdk.module.boot.6.layerCreateTime");
// Step 7: Miscellaneous // Step 7: Miscellaneous
@ -428,7 +411,6 @@ public final class ModuleBootstrap {
} }
// --add-reads, --add-exports/--add-opens, and --illegal-access // --add-reads, --add-exports/--add-opens, and --illegal-access
long t7 = System.nanoTime();
addExtraReads(bootLayer); addExtraReads(bootLayer);
boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer); boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer);
@ -446,7 +428,7 @@ public final class ModuleBootstrap {
exportedPackagesToOpen, exportedPackagesToOpen,
bootLayer, bootLayer,
extraExportsOrOpens); extraExportsOrOpens);
Counters.add("jdk.module.boot.7.adjustModulesTime", t7); Counters.add("jdk.module.boot.7.adjustModulesTime");
// save module finders for later use // save module finders for later use
if (savedModuleFinder != null) { if (savedModuleFinder != null) {
@ -468,8 +450,7 @@ public final class ModuleBootstrap {
} }
// total time to initialize // total time to initialize
Counters.add("jdk.module.boot.totalTime", t0); Counters.publish("jdk.module.boot.totalTime");
Counters.publish();
return bootLayer; return bootLayer;
} }
@ -1030,6 +1011,9 @@ public final class ModuleBootstrap {
private static final boolean PUBLISH_COUNTERS; private static final boolean PUBLISH_COUNTERS;
private static final boolean PRINT_COUNTERS; private static final boolean PRINT_COUNTERS;
private static Map<String, Long> counters; private static Map<String, Long> counters;
private static long startTime;
private static long previousTime;
static { static {
String s = System.getProperty("jdk.module.boot.usePerfData"); String s = System.getProperty("jdk.module.boot.usePerfData");
if (s == null) { if (s == null) {
@ -1043,27 +1027,44 @@ public final class ModuleBootstrap {
} }
/** /**
* Add a counter * Start counting time.
*/ */
static void add(String name, long start) { static void start() {
if (PUBLISH_COUNTERS || PRINT_COUNTERS) { if (PUBLISH_COUNTERS) {
counters.put(name, (System.nanoTime() - start)); startTime = previousTime = System.nanoTime();
}
}
/**
* Add a counter - storing the time difference between now and the
* previous add or the start.
*/
static void add(String name) {
if (PUBLISH_COUNTERS) {
long current = System.nanoTime();
long elapsed = current - previousTime;
previousTime = current;
counters.put(name, elapsed);
} }
} }
/** /**
* Publish the counters to the instrumentation buffer or stdout. * Publish the counters to the instrumentation buffer or stdout.
*/ */
static void publish() { static void publish(String totalTimeName) {
if (PUBLISH_COUNTERS || PRINT_COUNTERS) { if (PUBLISH_COUNTERS) {
long currentTime = System.nanoTime();
for (Map.Entry<String, Long> e : counters.entrySet()) { for (Map.Entry<String, Long> e : counters.entrySet()) {
String name = e.getKey(); String name = e.getKey();
long value = e.getValue(); long value = e.getValue();
if (PUBLISH_COUNTERS)
PerfCounter.newPerfCounter(name).set(value); PerfCounter.newPerfCounter(name).set(value);
if (PRINT_COUNTERS) if (PRINT_COUNTERS)
System.out.println(name + " = " + value); System.out.println(name + " = " + value);
} }
long elapsedTotal = currentTime - startTime;
PerfCounter.newPerfCounter(totalTimeName).set(elapsedTotal);
if (PRINT_COUNTERS)
System.out.println(totalTimeName + " = " + elapsedTotal);
} }
} }
} }