Skip to content

Commit ee790c2

Browse files
committed
[GR-41209] Module-aware Resource storage
PullRequest: graal/14430
2 parents 47c7088 + 571df36 commit ee790c2

File tree

6 files changed

+74
-51
lines changed

6 files changed

+74
-51
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@
3535
import java.util.Date;
3636
import java.util.Enumeration;
3737
import java.util.List;
38+
import java.util.Objects;
39+
import java.util.Set;
40+
import java.util.stream.Collectors;
41+
import java.util.stream.StreamSupport;
3842

43+
import com.oracle.svm.core.BuildPhaseProvider;
3944
import org.graalvm.collections.EconomicMap;
4045
import org.graalvm.collections.Pair;
4146
import org.graalvm.nativeimage.ImageSingletons;
@@ -67,11 +72,13 @@ public static Resources singleton() {
6772
}
6873

6974
/**
70-
* The hosted map used to collect registered resources. Using a {@link Pair} of (moduleName,
75+
* The hosted map used to collect registered resources. Using a {@link Pair} of (module,
7176
* resourceName) provides implementations for {@code hashCode()} and {@code equals()} needed for
72-
* the map keys.
77+
* the map keys. Hosted module instances differ to runtime instances, so the map that ends up in
78+
* the image heap is computed after the runtime module instances have been computed {see
79+
* com.oracle.svm.hosted.ModuleLayerFeature}.
7380
*/
74-
private final EconomicMap<Pair<String, String>, ResourceStorageEntry> resources = ImageHeapMap.create();
81+
private final EconomicMap<Pair<Module, String>, ResourceStorageEntry> resources = ImageHeapMap.create();
7582

7683
/**
7784
* Embedding a resource into an image is counted as a modification. Since all resources are
@@ -83,7 +90,7 @@ public static Resources singleton() {
8390
Resources() {
8491
}
8592

86-
public EconomicMap<Pair<String, String>, ResourceStorageEntry> getResourceStorage() {
93+
public EconomicMap<Pair<Module, String>, ResourceStorageEntry> getResourceStorage() {
8794
return resources;
8895
}
8996

@@ -103,6 +110,19 @@ public static String moduleName(Module module) {
103110
return module == null ? null : module.getName();
104111
}
105112

113+
private static Pair<Module, String> createStorageKey(Module module, String resourceName) {
114+
Module m = module != null && module.isNamed() ? module : null;
115+
return Pair.create(m, resourceName);
116+
}
117+
118+
public static Set<String> getIncludedResourcesModules() {
119+
return StreamSupport.stream(singleton().resources.getKeys().spliterator(), false)
120+
.map(Pair::getLeft)
121+
.filter(Objects::nonNull)
122+
.map(Module::getName)
123+
.collect(Collectors.toSet());
124+
}
125+
106126
public static byte[] inputStreamToByteArray(InputStream is) {
107127
try {
108128
return is.readAllBytes();
@@ -111,11 +131,16 @@ public static byte[] inputStreamToByteArray(InputStream is) {
111131
}
112132
}
113133

134+
@Platforms(Platform.HOSTED_ONLY.class)
114135
private static void addEntry(Module module, String resourceName, boolean isDirectory, byte[] data, boolean fromJar) {
115-
String moduleName = moduleName(module);
136+
VMError.guarantee(!BuildPhaseProvider.isAnalysisFinished(), "Trying to add a resource entry after analysis.");
137+
Module m = module != null && module.isNamed() ? module : null;
138+
if (m != null) {
139+
m = RuntimeModuleSupport.instance().getRuntimeModuleForHostedModule(m);
140+
}
116141
var resources = singleton().resources;
117142
synchronized (resources) {
118-
Pair<String, String> key = Pair.create(moduleName, resourceName);
143+
Pair<Module, String> key = createStorageKey(m, resourceName);
119144
ResourceStorageEntry entry = resources.get(key);
120145
if (entry == null) {
121146
if (singleton().lastModifiedTime == INVALID_TIMESTAMP) {
@@ -205,8 +230,7 @@ public static ResourceStorageEntry get(String name) {
205230

206231
public static ResourceStorageEntry get(Module module, String resourceName) {
207232
String canonicalResourceName = toCanonicalForm(resourceName);
208-
String moduleName = moduleName(module);
209-
ResourceStorageEntry entry = singleton().resources.get(Pair.create(moduleName, canonicalResourceName));
233+
ResourceStorageEntry entry = singleton().resources.get(createStorageKey(module, canonicalResourceName));
210234
if (entry == null) {
211235
return null;
212236
}
@@ -267,7 +291,7 @@ public static InputStream createInputStream(Module module, String resourceName)
267291
* If module is not specified or is an unnamed module and entry was not found as
268292
* classpath-resource we have to search for the resource in all modules in the image.
269293
*/
270-
for (Module m : BootModuleLayerSupport.instance().getBootLayer().modules()) {
294+
for (Module m : RuntimeModuleSupport.instance().getBootLayer().modules()) {
271295
entry = Resources.get(m, resourceName);
272296
if (entry != null) {
273297
break;
@@ -296,7 +320,7 @@ public static Enumeration<URL> createURLs(Module module, String resourceName) {
296320
boolean shouldAppendTrailingSlash = hasTrailingSlash(resourceName);
297321
/* If module was unspecified or unnamed, we have to consider all modules in the image */
298322
if (moduleName(module) == null) {
299-
for (Module m : BootModuleLayerSupport.instance().getBootLayer().modules()) {
323+
for (Module m : RuntimeModuleSupport.instance().getBootLayer().modules()) {
300324
ResourceStorageEntry entry = Resources.get(m, resourceName);
301325
addURLEntries(resourcesURLs, entry, m, shouldAppendTrailingSlash ? canonicalResourceName + '/' : canonicalResourceName);
302326
}
Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,35 @@
3030

3131
import com.oracle.svm.core.heap.UnknownObjectField;
3232

33-
public final class BootModuleLayerSupport {
33+
import java.util.function.Function;
3434

35-
public static BootModuleLayerSupport instance() {
36-
return ImageSingletons.lookup(BootModuleLayerSupport.class);
35+
public final class RuntimeModuleSupport {
36+
37+
public static RuntimeModuleSupport instance() {
38+
return ImageSingletons.lookup(RuntimeModuleSupport.class);
3739
}
3840

3941
@UnknownObjectField private ModuleLayer bootLayer;
4042

41-
@Platforms(Platform.HOSTED_ONLY.class)
43+
@Platforms(Platform.HOSTED_ONLY.class) //
44+
private Function<Module, Module> hostedToRuntimeModuleMapper;
45+
46+
@Platforms(Platform.HOSTED_ONLY.class) //
4247
public void setBootLayer(ModuleLayer bootLayer) {
4348
this.bootLayer = bootLayer;
4449
}
4550

4651
public ModuleLayer getBootLayer() {
4752
return bootLayer;
4853
}
54+
55+
@Platforms(Platform.HOSTED_ONLY.class) //
56+
public void setHostedToRuntimeModuleMapper(Function<Module, Module> hostedToRuntimeModuleMapper) {
57+
this.hostedToRuntimeModuleMapper = hostedToRuntimeModuleMapper;
58+
}
59+
60+
public Module getRuntimeModuleForHostedModule(Module hostedModule) {
61+
return hostedToRuntimeModuleMapper.apply(hostedModule);
62+
}
63+
4964
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ final class Target_java_lang_ModuleLayer {
3434
@SuppressWarnings("unused")
3535
@Substitute
3636
public static ModuleLayer boot() {
37-
return BootModuleLayerSupport.instance().getBootLayer();
37+
return RuntimeModuleSupport.instance().getBootLayer();
3838
}
3939
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/resources/NativeImageResourceFileSystem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ private void update(Entry e) {
651651
}
652652

653653
private void readAllEntries() {
654-
MapCursor<Pair<String, String>, ResourceStorageEntry> entries = Resources.singleton().getResourceStorage().getEntries();
654+
MapCursor<Pair<Module, String>, ResourceStorageEntry> entries = Resources.singleton().getResourceStorage().getEntries();
655655
while (entries.advance()) {
656656
byte[] name = getBytes(entries.getKey().getRight());
657657
IndexNode newIndexNode = new IndexNode(name, entries.getValue().isDirectory());

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import java.util.stream.Collectors;
5555
import java.util.stream.Stream;
5656

57+
import com.oracle.svm.core.jdk.Resources;
5758
import jdk.internal.module.DefaultRoots;
5859
import jdk.internal.module.ModuleBootstrap;
5960
import jdk.internal.module.SystemModuleFinders;
@@ -63,11 +64,13 @@
6364
import com.oracle.svm.core.SubstrateOptions;
6465
import com.oracle.svm.core.SubstrateUtil;
6566
import com.oracle.svm.core.feature.InternalFeature;
66-
import com.oracle.svm.core.jdk.BootModuleLayerSupport;
67+
import com.oracle.svm.core.jdk.RuntimeModuleSupport;
6768
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
6869
import com.oracle.svm.core.util.VMError;
6970
import com.oracle.svm.util.ModuleSupport;
7071
import com.oracle.svm.util.ReflectionUtil;
72+
import org.graalvm.nativeimage.Platform;
73+
import org.graalvm.nativeimage.Platforms;
7174

7275
/**
7376
* This feature:
@@ -126,7 +129,8 @@ public void duringSetup(DuringSetupAccess access) {
126129
.collect(Collectors.toSet());
127130
Function<String, ClassLoader> clf = moduleLayerFeatureUtils::getClassLoaderForBootLayerModule;
128131
ModuleLayer runtimeBootLayer = synthesizeRuntimeModuleLayer(new ArrayList<>(List.of(ModuleLayer.empty())), accessImpl.imageClassLoader, baseModules, Set.of(), clf, null);
129-
BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer);
132+
RuntimeModuleSupport.instance().setBootLayer(runtimeBootLayer);
133+
RuntimeModuleSupport.instance().setHostedToRuntimeModuleMapper(moduleLayerFeatureUtils::getOrCreateRuntimeModuleForHostedModule);
130134

131135
/*
132136
* Register an object replacer that will ensure all references to hosted module instances
@@ -136,21 +140,20 @@ public void duringSetup(DuringSetupAccess access) {
136140
}
137141

138142
private Object replaceHostedModules(Object source) {
139-
if (source instanceof Module) {
140-
Module module = (Module) source;
141-
return moduleLayerFeatureUtils.getOrCreateRuntimeModuleForHostedModule(module, module.getDescriptor());
143+
if (source instanceof Module module) {
144+
return moduleLayerFeatureUtils.getOrCreateRuntimeModuleForHostedModule(module);
142145
}
143146
return source;
144147
}
145148

146149
@Override
147150
public void afterRegistration(AfterRegistrationAccess access) {
148-
ImageSingletons.add(BootModuleLayerSupport.class, new BootModuleLayerSupport());
151+
ImageSingletons.add(RuntimeModuleSupport.class, new RuntimeModuleSupport());
149152

150153
List<Module> bootLayerAutomaticModules = ModuleLayer.boot().modules()
151154
.stream()
152155
.filter(m -> m.isNamed() && m.getDescriptor().isAutomatic())
153-
.collect(Collectors.toList());
156+
.toList();
154157
if (!bootLayerAutomaticModules.isEmpty()) {
155158
System.out.println("Warning: Detected automatic module(s) on the module-path of the image builder:" + System.lineSeparator() +
156159
bootLayerAutomaticModules.stream().map(ModuleLayerFeatureUtils::formatModule).collect(Collectors.joining(System.lineSeparator())) +
@@ -176,12 +179,7 @@ public void afterAnalysis(AfterAnalysisAccess access) {
176179
* is required when filtering the analysis reachable module set.
177180
*/
178181
Set<String> extraModules = ModuleLayerFeatureUtils.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_ADDED_MODULES);
179-
Set<String> includedResourceModules = ImageSingletons.lookup(ResourcesFeature.class).includedResourcesModules
180-
.stream()
181-
.map(Module::getName)
182-
.filter(Objects::nonNull)
183-
.collect(Collectors.toSet());
184-
extraModules.addAll(includedResourceModules);
182+
extraModules.addAll(Resources.getIncludedResourcesModules());
185183
extraModules.stream().filter(Predicate.not(ModuleSupport.nonExplicitModules::contains)).forEach(moduleName -> {
186184
Optional<?> module = accessImpl.imageClassLoader.findModule(moduleName);
187185
if (module.isEmpty()) {
@@ -219,7 +217,7 @@ public void afterAnalysis(AfterAnalysisAccess access) {
219217
Set<String> rootModules = calculateRootModules(extraModules);
220218
List<ModuleLayer> runtimeModuleLayers = synthesizeRuntimeModuleLayers(accessImpl, reachableModuleLayers, runtimeImageNamedModules, analysisReachableSyntheticModules, rootModules);
221219
ModuleLayer runtimeBootLayer = runtimeModuleLayers.get(0);
222-
BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer);
220+
RuntimeModuleSupport.instance().setBootLayer(runtimeBootLayer);
223221

224222
/*
225223
* Ensure that runtime modules have the same relations (i.e., reads, opens and exports) as
@@ -416,7 +414,7 @@ private ModuleLayer synthesizeRuntimeModuleLayer(List<ModuleLayer> parentLayers,
416414
runtimeModuleLayer = moduleLayerFeatureUtils.createNewModuleLayerInstance(runtimeModuleLayerConfiguration);
417415
Map<String, Module> nameToModule = moduleLayerFeatureUtils.synthesizeNameToModule(runtimeModuleLayer, clf);
418416
for (Module syntheticModule : syntheticModules) {
419-
Module runtimeSyntheticModule = moduleLayerFeatureUtils.getOrCreateRuntimeModuleForHostedModule(syntheticModule, syntheticModule.getDescriptor());
417+
Module runtimeSyntheticModule = moduleLayerFeatureUtils.getOrCreateRuntimeModuleForHostedModule(syntheticModule);
420418
nameToModule.putIfAbsent(runtimeSyntheticModule.getName(), runtimeSyntheticModule);
421419
moduleLayerFeatureUtils.patchModuleLayerField(runtimeSyntheticModule, runtimeModuleLayer);
422420
}
@@ -540,6 +538,7 @@ private void patchRuntimeModuleLayer(ModuleLayer runtimeModuleLayer, Map<String,
540538
runtimeModuleLayer.modules();
541539
}
542540

541+
@Platforms(Platform.HOSTED_ONLY.class)
543542
private static final class ModuleLayerFeatureUtils {
544543
private final Map<ClassLoader, Map<String, Module>> runtimeModules;
545544
private final ImageClassLoader imageClassLoader;
@@ -731,9 +730,9 @@ public Module getRuntimeModuleForHostedModule(ClassLoader loader, String hostedM
731730
}
732731
}
733732

734-
public Module getOrCreateRuntimeModuleForHostedModule(Module hostedModule, ModuleDescriptor runtimeModuleDescriptor) {
733+
public Module getOrCreateRuntimeModuleForHostedModule(Module hostedModule) {
735734
if (hostedModule.isNamed()) {
736-
return getOrCreateRuntimeModuleForHostedModule(hostedModule.getClassLoader(), hostedModule.getName(), runtimeModuleDescriptor);
735+
return getOrCreateRuntimeModuleForHostedModule(hostedModule.getClassLoader(), hostedModule.getName(), hostedModule.getDescriptor());
737736
} else {
738737
return hostedModule == everyoneModule ? everyoneModule : allUnnamedModule;
739738
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import java.util.Arrays;
3838
import java.util.Collection;
3939
import java.util.Collections;
40-
import java.util.HashSet;
4140
import java.util.List;
4241
import java.util.Locale;
4342
import java.util.Set;
@@ -47,7 +46,6 @@
4746
import java.util.concurrent.TimeUnit;
4847
import java.util.concurrent.atomic.LongAdder;
4948
import java.util.regex.Pattern;
50-
import java.util.stream.Collectors;
5149

5250
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
5351
import org.graalvm.compiler.debug.DebugContext;
@@ -137,8 +135,6 @@ public static class Options {
137135
private int loadedConfigurations;
138136
private ImageClassLoader imageClassLoader;
139137

140-
public final Set<Module> includedResourcesModules = new HashSet<>();
141-
142138
private class ResourcesRegistryImpl extends ConditionalConfigurationRegistry implements ResourcesRegistry {
143139
private final ConfigurationTypeResolver configurationTypeResolver;
144140

@@ -228,7 +224,6 @@ private static final class ResourceCollectorImpl implements ResourceCollector {
228224
private final DebugContext debugContext;
229225
private final ResourcePattern[] includePatterns;
230226
private final ResourcePattern[] excludePatterns;
231-
private final Set<Module> includedResourcesModules;
232227

233228
private static final int WATCHDOG_RESET_AFTER_EVERY_N_RESOURCES = 1000;
234229
private static final int WATCHDOG_INITIAL_WARNING_AFTER_N_SECONDS = 60;
@@ -239,12 +234,10 @@ private static final class ResourceCollectorImpl implements ResourceCollector {
239234
private volatile String currentlyProcessedEntry;
240235
ScheduledExecutorService scheduledExecutor;
241236

242-
private ResourceCollectorImpl(DebugContext debugContext, ResourcePattern[] includePatterns, ResourcePattern[] excludePatterns, Set<Module> includedResourcesModules,
243-
Runnable heartbeatCallback) {
237+
private ResourceCollectorImpl(DebugContext debugContext, ResourcePattern[] includePatterns, ResourcePattern[] excludePatterns, Runnable heartbeatCallback) {
244238
this.debugContext = debugContext;
245239
this.includePatterns = includePatterns;
246240
this.excludePatterns = excludePatterns;
247-
this.includedResourcesModules = includedResourcesModules;
248241

249242
this.heartbeatCallback = heartbeatCallback;
250243
this.reachedResourceEntries = new LongAdder();
@@ -307,21 +300,13 @@ public boolean isIncluded(Module module, String resourceName, URI resource) {
307300

308301
@Override
309302
public void addResource(Module module, String resourceName, InputStream resourceStream, boolean fromJar) {
310-
collectModule(module);
311303
registerResource(debugContext, module, resourceName, resourceStream, fromJar);
312304
}
313305

314306
@Override
315307
public void addDirectoryResource(Module module, String dir, String content, boolean fromJar) {
316-
collectModule(module);
317308
registerDirectoryResource(debugContext, module, dir, content, fromJar);
318309
}
319-
320-
private void collectModule(Module module) {
321-
if (module != null && module.isNamed()) {
322-
includedResourcesModules.add(module);
323-
}
324-
}
325310
}
326311

327312
@Override
@@ -337,7 +322,7 @@ public void duringAnalysis(DuringAnalysisAccess access) {
337322
ResourcePattern[] includePatterns = compilePatterns(resourcePatternWorkSet);
338323
ResourcePattern[] excludePatterns = compilePatterns(excludedResourcePatterns);
339324
DebugContext debugContext = duringAnalysisAccess.getDebugContext();
340-
ResourceCollectorImpl collector = new ResourceCollectorImpl(debugContext, includePatterns, excludePatterns, includedResourcesModules, duringAnalysisAccess.bb.getHeartbeatCallback());
325+
ResourceCollectorImpl collector = new ResourceCollectorImpl(debugContext, includePatterns, excludePatterns, duringAnalysisAccess.bb.getHeartbeatCallback());
341326
try {
342327
collector.prepareProgressReporter();
343328
ImageSingletons.lookup(ClassLoaderSupport.class).collectResources(collector);
@@ -351,7 +336,7 @@ private ResourcePattern[] compilePatterns(Set<String> patterns) {
351336
return patterns.stream()
352337
.filter(s -> s.length() > 0)
353338
.map(this::makeResourcePattern)
354-
.collect(Collectors.toList())
339+
.toList()
355340
.toArray(new ResourcePattern[]{});
356341
}
357342

0 commit comments

Comments
 (0)