8237878: Improve ModuleLoaderMap datastructures

Reviewed-by: alanb, forax
This commit is contained in:
Claes Redestad 2020-02-10 13:58:12 +01:00
parent c23d1de2f8
commit 326a939e1b
5 changed files with 104 additions and 81 deletions

@ -1094,13 +1094,14 @@ public final class Module implements AnnotatedElement {
// map each module to a class loader
ClassLoader pcl = ClassLoaders.platformClassLoader();
boolean isModuleLoaderMapper = ModuleLoaderMap.isBuiltinMapper(clf);
for (int index = 0; index < numModules; index++) {
String name = resolvedModules[index].name();
ClassLoader loader = clf.apply(name);
if (loader == null || loader == pcl) {
if (!(clf instanceof ModuleLoaderMap.Mapper)) {
if (!isModuleLoaderMapper) {
throw new IllegalArgumentException("loader can't be 'null'"
+ " or the platform class loader");
}

@ -79,7 +79,7 @@ public final class ResolvedModule {
* @return The module descriptor
*/
ModuleDescriptor descriptor() {
return reference().descriptor();
return mref.descriptor();
}
/**
@ -93,7 +93,7 @@ public final class ResolvedModule {
* @return The module name
*/
public String name() {
return reference().descriptor().name();
return mref.descriptor().name();
}
/**

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,8 +28,8 @@ package jdk.internal.module;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import jdk.internal.misc.VM;
@ -39,26 +39,26 @@ import jdk.internal.misc.VM;
final class ArchivedModuleGraph {
private static ArchivedModuleGraph archivedModuleGraph;
private final String mainModule;
private final boolean hasSplitPackages;
private final boolean hasIncubatorModules;
private final ModuleFinder finder;
private final Configuration configuration;
private final Function<String, ClassLoader> classLoaderFunction;
private final Map<String, Set<String>> concealedPackagesToOpen;
private final Map<String, Set<String>> exportedPackagesToOpen;
private ArchivedModuleGraph(String mainModule,
boolean hasSplitPackages,
boolean hasIncubatorModules,
ModuleFinder finder,
Configuration configuration,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen) {
this.mainModule = mainModule;
public ArchivedModuleGraph(boolean hasSplitPackages,
boolean hasIncubatorModules,
ModuleFinder finder,
Configuration configuration,
Function<String, ClassLoader> classLoaderFunction,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen) {
this.hasSplitPackages = hasSplitPackages;
this.hasIncubatorModules = hasIncubatorModules;
this.finder = finder;
this.configuration = configuration;
this.classLoaderFunction = classLoaderFunction;
this.concealedPackagesToOpen = concealedPackagesToOpen;
this.exportedPackagesToOpen = exportedPackagesToOpen;
}
@ -71,6 +71,10 @@ final class ArchivedModuleGraph {
return configuration;
}
Function<String, ClassLoader> classLoaderFunction() {
return classLoaderFunction;
}
Map<String, Set<String>> concealedPackagesToOpen() {
return concealedPackagesToOpen;
}
@ -92,7 +96,8 @@ final class ArchivedModuleGraph {
*/
static ArchivedModuleGraph get(String mainModule) {
ArchivedModuleGraph graph = archivedModuleGraph;
if (graph != null && Objects.equals(mainModule, graph.mainModule)) {
// We only allow the unnamed module (default) case for now
if (mainModule == null) {
return graph;
} else {
return null;
@ -102,23 +107,8 @@ final class ArchivedModuleGraph {
/**
* Archive the module graph for the given initial module.
*/
static void archive(String mainModule,
boolean hasSplitPackages,
boolean hasIncubatorModules,
ModuleFinder finder,
Configuration configuration,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen) {
if (mainModule != null) {
throw new UnsupportedOperationException();
}
archivedModuleGraph = new ArchivedModuleGraph(mainModule,
hasSplitPackages,
hasIncubatorModules,
finder,
configuration,
concealedPackagesToOpen,
exportedPackagesToOpen);
static void archive(ArchivedModuleGraph graph) {
archivedModuleGraph = graph;
}
static {

@ -370,7 +370,12 @@ public final class ModuleBootstrap {
// loader.
// mapping of modules to class loaders
Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
Function<String, ClassLoader> clf;
if (archivedModuleGraph != null) {
clf = archivedModuleGraph.classLoaderFunction();
} else {
clf = ModuleLoaderMap.mappingFunction(cf);
}
// check that all modules to be mapped to the boot loader will be
// loaded from the runtime image
@ -440,13 +445,14 @@ public final class ModuleBootstrap {
// Module graph can be archived at CDS dump time. Only allow the
// unnamed module case for now.
if (canArchive && (mainModule == null)) {
ArchivedModuleGraph.archive(mainModule,
hasSplitPackages,
hasIncubatorModules,
systemModuleFinder,
cf,
concealedPackagesToOpen,
exportedPackagesToOpen);
ArchivedModuleGraph.archive(
new ArchivedModuleGraph(hasSplitPackages,
hasIncubatorModules,
systemModuleFinder,
cf,
clf,
concealedPackagesToOpen,
exportedPackagesToOpen));
}
// total time to initialize
@ -737,7 +743,6 @@ public final class ModuleBootstrap {
Modules.addExports(m, pn, other);
}
}
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,14 +28,12 @@ package jdk.internal.module;
import java.lang.module.Configuration;
import java.lang.module.ResolvedModule;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import jdk.internal.loader.ClassLoaders;
/**
* Supports the mapping of modules to class loaders. The set of modules mapped
* to the boot and platform class loaders is generated at build time from
@ -46,16 +44,55 @@ public final class ModuleLoaderMap {
/**
* Maps the system modules to the built-in class loaders.
*/
public static final class Mapper implements Function<String, ClassLoader> {
private final Map<String, ClassLoader> map;
private static final class Mapper implements Function<String, ClassLoader> {
Mapper(Map<String, ClassLoader> map) {
this.map = map; // defensive copy not needed
private static final ClassLoader PLATFORM_CLASSLOADER =
ClassLoaders.platformClassLoader();
private static final ClassLoader APP_CLASSLOADER =
ClassLoaders.appClassLoader();
private static final Integer PLATFORM_LOADER_INDEX = 1;
private static final Integer APP_LOADER_INDEX = 2;
/**
* Map from module to a class loader index. The index is resolved to the
* actual class loader in {@code apply}.
*/
private final Map<String, Integer> map;
/**
* Creates a Mapper to map module names in the given Configuration to
* built-in classloaders.
*
* As a proxy for the actual classloader, we store an easily archiveable
* index value in the internal map. The index is stored as a boxed value
* so that we can cheaply do identity comparisons during bootstrap.
*/
Mapper(Configuration cf) {
var map = new HashMap<String, Integer>();
for (ResolvedModule resolvedModule : cf.modules()) {
String mn = resolvedModule.name();
if (!Modules.bootModules.contains(mn)) {
if (Modules.platformModules.contains(mn)) {
map.put(mn, PLATFORM_LOADER_INDEX);
} else {
map.put(mn, APP_LOADER_INDEX);
}
}
}
this.map = map;
}
@Override
public ClassLoader apply(String name) {
return map.get(name);
Integer loader = map.get(name);
if (loader == APP_LOADER_INDEX) {
return APP_CLASSLOADER;
} else if (loader == PLATFORM_LOADER_INDEX) {
return PLATFORM_CLASSLOADER;
} else { // BOOT_LOADER_INDEX
return null;
}
}
}
@ -63,50 +100,40 @@ public final class ModuleLoaderMap {
* Returns the names of the modules defined to the boot loader.
*/
public static Set<String> bootModules() {
// The list of boot modules generated at build time.
String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
Set<String> bootModules = new HashSet<>(BOOT_MODULES.length);
for (String mn : BOOT_MODULES) {
bootModules.add(mn);
}
return bootModules;
return Modules.bootModules;
}
/**
* Returns the names of the modules defined to the platform loader.
*/
public static Set<String> platformModules() {
// The list of platform modules generated at build time.
String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
Set<String> platformModules = new HashSet<>(PLATFORM_MODULES.length);
for (String mn : PLATFORM_MODULES) {
platformModules.add(mn);
}
return platformModules;
return Modules.platformModules;
}
private static class Modules {
// list of boot modules is generated at build time.
private static final Set<String> bootModules =
Set.of(new String[] { "@@BOOT_MODULE_NAMES@@" });
// list of platform modules is generated at build time.
private static final Set<String> platformModules =
Set.of(new String[] { "@@PLATFORM_MODULE_NAMES@@" });
}
/**
* Returns the function to map modules in the given configuration to the
* Returns a function to map modules in the given configuration to the
* built-in class loaders.
*/
static Function<String, ClassLoader> mappingFunction(Configuration cf) {
Set<String> bootModules = bootModules();
Set<String> platformModules = platformModules();
return new Mapper(cf);
}
ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
ClassLoader appClassLoader = ClassLoaders.appClassLoader();
Map<String, ClassLoader> map = new HashMap<>();
for (ResolvedModule resolvedModule : cf.modules()) {
String mn = resolvedModule.name();
if (!bootModules.contains(mn)) {
if (platformModules.contains(mn)) {
map.put(mn, platformClassLoader);
} else {
map.put(mn, appClassLoader);
}
}
}
return new Mapper(map);
/**
* When defining modules for a configuration, we only allow defining modules
* to the boot or platform classloader if the ClassLoader mapping function
* originate from here.
*/
public static boolean isBuiltinMapper(Function<String, ClassLoader> clf) {
return clf instanceof Mapper;
}
}