Skip to content

Commit a0927e4

Browse files
committed
Replace ImageIncludeBuiltinModules special handling with generic per-module class-init
1 parent ee260eb commit a0927e4

File tree

10 files changed

+179
-206
lines changed

10 files changed

+179
-206
lines changed

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/MacroOptionHandler.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ private void applyEnabled(MacroOption.EnabledOption enabledOption, String argume
8383
BuildConfiguration config = nativeImage.config;
8484
if (!config.useJavaModules()) {
8585
enabledOption.forEachPropertyValue(config, "ImageBuilderBootClasspath8", entry -> nativeImage.addImageBuilderBootClasspath(ClasspathUtils.stringToClasspath(entry)), PATH_SEPARATOR_REGEX);
86-
} else {
87-
enabledOption.forEachPropertyValue(config, "ImageIncludeBuiltinModules", entry -> nativeImage.addImageIncludeBuiltinModules(entry), ",");
8886
}
8987

9088
if (!enabledOption.forEachPropertyValue(config, "ImageBuilderClasspath", entry -> nativeImage.addImageBuilderClasspath(ClasspathUtils.stringToClasspath(entry)), PATH_SEPARATOR_REGEX)) {

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@
9191
import com.oracle.svm.driver.MacroOption.EnabledOption;
9292
import com.oracle.svm.driver.MacroOption.MacroOptionKind;
9393
import com.oracle.svm.driver.MacroOption.Registry;
94-
import com.oracle.svm.hosted.AbstractNativeImageClassLoaderSupport;
9594
import com.oracle.svm.hosted.NativeImageGeneratorRunner;
9695
import com.oracle.svm.hosted.NativeImageSystemClassLoader;
9796
import com.oracle.svm.util.ModuleSupport;
@@ -239,7 +238,6 @@ private static <T> String oR(OptionKey<T> option) {
239238
private final ArrayList<String> imageBuilderArgs = new ArrayList<>();
240239
private final LinkedHashSet<Path> imageBuilderClasspath = new LinkedHashSet<>();
241240
private final LinkedHashSet<Path> imageBuilderBootClasspath = new LinkedHashSet<>();
242-
private final LinkedHashSet<String> imageIncludeBuiltinModules = new LinkedHashSet<>();
243241
private final ArrayList<String> imageBuilderJavaArgs = new ArrayList<>();
244242
private final LinkedHashSet<Path> imageClasspath = new LinkedHashSet<>();
245243
private final LinkedHashSet<Path> imageProvidedClasspath = new LinkedHashSet<>();
@@ -1194,9 +1192,6 @@ private int completeImageBuild() {
11941192
// The following two are for backwards compatibility reasons. They should be removed.
11951193
imageBuilderJavaArgs.add("-Djdk.internal.lambda.eagerlyInitialize=false");
11961194
imageBuilderJavaArgs.add("-Djava.lang.invoke.InnerClassLambdaMetafactory.initializeLambdas=false");
1197-
if (!imageIncludeBuiltinModules.isEmpty()) {
1198-
imageBuilderJavaArgs.add("-D" + AbstractNativeImageClassLoaderSupport.PROPERTY_IMAGEINCLUDEBUILTINMODULES + "=" + String.join(",", imageIncludeBuiltinModules));
1199-
}
12001195

12011196
/* After JavaArgs consolidation add the user provided JavaArgs */
12021197
boolean afterOption = false;
@@ -1623,10 +1618,6 @@ void addImageBuilderBootClasspath(Path classpath) {
16231618
imageBuilderBootClasspath.add(canonicalize(classpath));
16241619
}
16251620

1626-
public void addImageIncludeBuiltinModules(String moduleName) {
1627-
imageIncludeBuiltinModules.add(moduleName);
1628-
}
1629-
16301621
void addImageBuilderJavaArgs(String... javaArgs) {
16311622
addImageBuilderJavaArgs(Arrays.asList(javaArgs));
16321623
}

substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java

Lines changed: 106 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,23 @@
2525
package com.oracle.svm.hosted;
2626

2727
import java.io.File;
28+
import java.io.IOException;
2829
import java.lang.module.Configuration;
2930
import java.lang.module.ModuleDescriptor;
3031
import java.lang.module.ModuleFinder;
32+
import java.lang.module.ModuleReader;
33+
import java.lang.module.ModuleReference;
3134
import java.nio.file.Path;
3235
import java.nio.file.Paths;
36+
import java.util.ArrayDeque;
37+
import java.util.ArrayList;
3338
import java.util.Arrays;
3439
import java.util.Collections;
40+
import java.util.Deque;
41+
import java.util.HashMap;
3542
import java.util.HashSet;
3643
import java.util.List;
44+
import java.util.Map;
3745
import java.util.Objects;
3846
import java.util.Optional;
3947
import java.util.Set;
@@ -48,7 +56,6 @@
4856
import com.oracle.svm.core.option.SubstrateOptionsParser;
4957
import com.oracle.svm.core.util.UserError;
5058
import com.oracle.svm.core.util.VMError;
51-
import com.oracle.svm.util.ModuleSupport;
5259

5360
import jdk.internal.module.Modules;
5461

@@ -59,22 +66,28 @@ public class NativeImageClassLoaderSupport extends AbstractNativeImageClassLoade
5966

6067
private final ClassLoader classLoader;
6168
private final ModuleLayer moduleLayerForImageBuild;
69+
private final Map<String, Set<Module>> packageToModuleNames;
6270

6371
NativeImageClassLoaderSupport(ClassLoader defaultSystemClassLoader, String[] classpath, String[] modulePath) {
6472
super(defaultSystemClassLoader, classpath);
6573

74+
packageToModuleNames = new HashMap<>();
75+
6676
imagemp = Arrays.stream(modulePath).map(Paths::get).collect(Collectors.toUnmodifiableList());
6777
buildmp = Arrays.stream(System.getProperty("jdk.module.path", "").split(File.pathSeparator)).map(Paths::get).collect(Collectors.toUnmodifiableList());
6878

6979
ModuleLayer moduleLayer = createModuleLayer(imagemp.toArray(Path[]::new), classPathClassLoader);
70-
if (moduleLayer.modules().isEmpty()) {
71-
this.moduleLayerForImageBuild = null;
72-
classLoader = classPathClassLoader;
73-
} else {
74-
adjustBootLayerQualifiedExports(moduleLayer);
75-
this.moduleLayerForImageBuild = moduleLayer;
76-
classLoader = getSingleClassloader(moduleLayer);
80+
adjustBootLayerQualifiedExports(moduleLayer);
81+
for (ModuleLayer layer : allLayers(moduleLayer)) {
82+
for (Module module : layer.modules()) {
83+
for (String packageName : module.getDescriptor().packages()) {
84+
addToPackageNameModules(module, packageName);
85+
}
86+
}
7787
}
88+
// dumpPackageNameModulesMapping();
89+
moduleLayerForImageBuild = moduleLayer;
90+
classLoader = getSingleClassloader(moduleLayer);
7891
}
7992

8093
private static ModuleLayer createModuleLayer(Path[] modulePaths, ClassLoader parent) {
@@ -89,6 +102,56 @@ private static ModuleLayer createModuleLayer(Path[] modulePaths, ClassLoader par
89102
return ModuleLayer.defineModulesWithOneLoader(configuration, List.of(ModuleLayer.boot()), parent).layer();
90103
}
91104

105+
private List<ModuleLayer> allLayers(ModuleLayer moduleLayer) {
106+
/** Implementation taken from {@link ModuleLayer#layers()} */
107+
List<ModuleLayer> allLayers = new ArrayList<>();
108+
Set<ModuleLayer> visited = new HashSet<>();
109+
Deque<ModuleLayer> stack = new ArrayDeque<>();
110+
visited.add(moduleLayer);
111+
stack.push(moduleLayer);
112+
113+
while (!stack.isEmpty()) {
114+
ModuleLayer layer = stack.pop();
115+
allLayers.add(layer);
116+
117+
// push in reverse order
118+
for (int i = layer.parents().size() - 1; i >= 0; i--) {
119+
ModuleLayer parent = layer.parents().get(i);
120+
if (!visited.contains(parent)) {
121+
visited.add(parent);
122+
stack.push(parent);
123+
}
124+
}
125+
}
126+
return allLayers;
127+
}
128+
129+
private void addToPackageNameModules(Module moduleName, String packageName) {
130+
Set<Module> prevValue = packageToModuleNames.get(packageName);
131+
if (prevValue == null) {
132+
/* Mostly packageName is only used in a single module */
133+
packageToModuleNames.put(packageName, Collections.singleton(moduleName));
134+
} else if (prevValue.size() == 1) {
135+
/* Transition to HashSet - happens rarely */
136+
HashSet<Module> newValue = new HashSet<>();
137+
newValue.add(prevValue.iterator().next());
138+
newValue.add(moduleName);
139+
packageToModuleNames.put(packageName, newValue);
140+
} else if (prevValue.size() > 1) {
141+
/* Add to exiting HashSet - happens rarely */
142+
prevValue.add(moduleName);
143+
}
144+
}
145+
146+
public void dumpPackageNameModulesMapping() {
147+
packageToModuleNames.entrySet().stream()
148+
.sorted(Map.Entry.comparingByKey())
149+
.map(e -> e.getKey() + " -> " + e.getValue().stream()
150+
.map(Module::getName)
151+
.collect(Collectors.joining(", ")))
152+
.forEach(System.out::println);
153+
}
154+
92155
private void adjustBootLayerQualifiedExports(ModuleLayer layer) {
93156
/*
94157
* For all qualified exports packages of modules in the the boot layer we check if layer
@@ -137,9 +200,6 @@ List<Path> applicationModulePath() {
137200

138201
@Override
139202
public Optional<Module> findModule(String moduleName) {
140-
if (moduleLayerForImageBuild == null) {
141-
return Optional.empty();
142-
}
143203
return moduleLayerForImageBuild.findModule(moduleName);
144204
}
145205

@@ -227,79 +287,67 @@ private static UserError.UserException userErrorAddExportsAndOpens(String origin
227287

228288
@Override
229289
Class<?> loadClassFromModule(Object module, String className) throws ClassNotFoundException {
230-
if (module == null) {
231-
return Class.forName(className, false, classPathClassLoader);
232-
}
233-
if (!(module instanceof Module)) {
234-
throw new IllegalArgumentException("Argument `module` is not an instance of java.lang.Module");
235-
}
290+
assert module instanceof Module : "Argument `module` is not an instance of java.lang.Module";
236291
Module m = (Module) module;
237-
if (m.getClassLoader() != classLoader) {
238-
throw new IllegalArgumentException("Argument `module` is java.lang.Module from different ClassLoader");
239-
}
240-
String moduleClassName = className;
241-
if (moduleClassName.isEmpty()) {
242-
moduleClassName = m.getDescriptor().mainClass().orElseThrow(
243-
() -> UserError.abort("module %s does not have a ModuleMainClass attribute, use -m <module>/<main-class>", m.getName()));
244-
}
245-
Class<?> clazz = Class.forName(m, moduleClassName);
246-
if (clazz == null) {
247-
throw new ClassNotFoundException(moduleClassName);
248-
}
249-
return clazz;
292+
assert m.getClassLoader() == classLoader : "Argument `module` is java.lang.Module from different ClassLoader";
293+
return Class.forName(m, className);
294+
}
295+
296+
@Override
297+
Optional<String> getMainClassFromModule(Object module) {
298+
assert module instanceof Module : "Argument `module` is not an instance of java.lang.Module";
299+
return ((Module) module).getDescriptor().mainClass();
250300
}
251301

252302
@Override
253303
ClassLoader getClassLoader() {
254304
return classLoader;
255305
}
256306

257-
private static class ClassInitWithModules extends ClassInit {
307+
private class ClassInitWithModules extends ClassInit {
258308

259-
ClassInitWithModules(ForkJoinPool executor, ImageClassLoader imageClassLoader, AbstractNativeImageClassLoaderSupport nativeImageClassLoader) {
260-
super(executor, imageClassLoader, nativeImageClassLoader);
309+
ClassInitWithModules(ForkJoinPool executor, ImageClassLoader imageClassLoader) {
310+
super(executor, imageClassLoader);
261311
}
262312

263313
@Override
264314
protected void init() {
265-
Set<String> modules = new HashSet<>();
266-
modules.add("jdk.internal.vm.ci");
267-
268-
addOptionalModule(modules, "org.graalvm.sdk");
269-
addOptionalModule(modules, "jdk.internal.vm.compiler");
270-
addOptionalModule(modules, "com.oracle.graal.graal_enterprise");
315+
List<String> requiresInit = Arrays.asList(
316+
"jdk.internal.vm.ci", "jdk.internal.vm.compiler", "com.oracle.graal.graal_enterprise",
317+
"org.graalvm.sdk", "org.graalvm.truffle");
271318

272-
String includeModulesStr = System.getProperty(PROPERTY_IMAGEINCLUDEBUILTINMODULES);
273-
if (includeModulesStr != null) {
274-
modules.addAll(Arrays.asList(includeModulesStr.split(",")));
275-
}
276-
277-
for (String moduleResource : ModuleSupport.getSystemModuleResources(modules)) {
278-
handleClassInModuleResource(moduleResource);
319+
for (ModuleReference moduleReference : ModuleFinder.ofSystem().findAll()) {
320+
if (requiresInit.contains(moduleReference.descriptor().name())) {
321+
initModule(moduleReference);
322+
}
279323
}
280-
281-
for (String moduleResource : ModuleSupport.getModuleResources(nativeImageClassLoader.modulepath())) {
282-
handleClassInModuleResource(moduleResource);
324+
for (ModuleReference moduleReference : ModuleFinder.of(modulepath().toArray(Path[]::new)).findAll()) {
325+
initModule(moduleReference);
283326
}
284327

285328
super.init();
286329
}
287330

288-
private void handleClassInModuleResource(String moduleResource) {
289-
if (moduleResource.endsWith(CLASS_EXTENSION)) {
290-
executor.execute(() -> handleClassFileName(classFileWithoutSuffix(moduleResource), '/'));
331+
private void initModule(ModuleReference moduleReference) {
332+
Optional<Module> optionalModule = findModule(moduleReference.descriptor().name());
333+
if (optionalModule.isEmpty()) {
334+
return;
291335
}
292-
}
293-
294-
private static void addOptionalModule(Set<String> modules, String name) {
295-
if (ModuleSupport.hasSystemModule(name)) {
296-
modules.add(name);
336+
try (ModuleReader moduleReader = moduleReference.open()) {
337+
Module module = optionalModule.get();
338+
moduleReader.list().forEach(moduleResource -> {
339+
if (moduleResource.endsWith(CLASS_EXTENSION)) {
340+
executor.execute(() -> handleClassFileName(module, moduleResource, '/'));
341+
}
342+
});
343+
} catch (IOException e) {
344+
throw new RuntimeException("Unable get list of resources in module" + moduleReference.descriptor().name(), e);
297345
}
298346
}
299347
}
300348

301349
@Override
302350
public void initAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoader) {
303-
new ClassInitWithModules(executor, imageClassLoader, this).init();
351+
new ClassInitWithModules(executor, imageClassLoader).init();
304352
}
305353
}

0 commit comments

Comments
 (0)