Skip to content

Commit d5cebd7

Browse files
committed
[GR-57350] Make resources layer aware
PullRequest: graal/19729
2 parents 53d6f05 + 6c8a04e commit d5cebd7

File tree

8 files changed

+100
-56
lines changed

8 files changed

+100
-56
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,7 @@ public Object[] getEnumConstantsShared() {
10121012
@Substitute
10131013
public InputStream getResourceAsStream(String resourceName) {
10141014
String resolvedName = resolveName(resourceName);
1015-
return Resources.singleton().createInputStream(companion.module, resolvedName);
1015+
return Resources.createInputStream(companion.module, resolvedName);
10161016
}
10171017

10181018
@KeepOriginal

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

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@
3434
import java.util.Arrays;
3535
import java.util.Collections;
3636
import java.util.Date;
37+
import java.util.EnumSet;
3738
import java.util.Enumeration;
3839
import java.util.List;
3940
import java.util.Objects;
4041
import java.util.Set;
42+
import java.util.function.BiConsumer;
4143
import java.util.stream.Collectors;
4244
import java.util.stream.StreamSupport;
4345

@@ -53,6 +55,7 @@
5355
import com.oracle.svm.core.ClassLoaderSupport.ConditionWithOrigin;
5456
import com.oracle.svm.core.MissingRegistrationUtils;
5557
import com.oracle.svm.core.SubstrateOptions;
58+
import com.oracle.svm.core.SubstrateUtil;
5659
import com.oracle.svm.core.configure.ConditionalRuntimeValue;
5760
import com.oracle.svm.core.configure.RuntimeConditionSet;
5861
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
@@ -67,6 +70,9 @@
6770
import com.oracle.svm.core.jdk.resources.CompressedGlobTrie.CompressedGlobTrie;
6871
import com.oracle.svm.core.jdk.resources.CompressedGlobTrie.GlobTrieNode;
6972
import com.oracle.svm.core.jdk.resources.CompressedGlobTrie.GlobUtils;
73+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
74+
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
75+
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
7076
import com.oracle.svm.core.util.ImageHeapMap;
7177
import com.oracle.svm.core.util.VMError;
7278
import com.oracle.svm.util.LogUtils;
@@ -78,15 +84,29 @@
7884
* Registered resources are then available from DynamicHub#getResource classes and
7985
* {@link Target_java_lang_ClassLoader class loaders}.
8086
*/
81-
public final class Resources {
87+
public final class Resources implements MultiLayeredImageSingleton, UnsavedSingleton {
8288

8389
private static final int INVALID_TIMESTAMP = -1;
8490
public static final char RESOURCES_INTERNAL_PATH_SEPARATOR = '/';
8591

92+
/**
93+
* @return the singleton corresponding to this layer's resources in a layered build, the unique
94+
* singleton otherwise
95+
*/
96+
@Platforms(Platform.HOSTED_ONLY.class)
8697
public static Resources singleton() {
8798
return ImageSingletons.lookup(Resources.class);
8899
}
89100

101+
/**
102+
* @return an array of singletons corresponding to all layers in a layered build, or an array
103+
* with a single element otherwise
104+
*/
105+
public static Resources[] layeredSingletons() {
106+
assert !SubstrateUtil.HOSTED : "Accessing all layers resources at build time";
107+
return MultiLayeredImageSingleton.getAllLayers(Resources.class);
108+
}
109+
90110
/**
91111
* The hosted map used to collect registered resources. Using a {@link ModuleResourceKey} of
92112
* (module, resourceName) provides implementations for {@code hashCode()} and {@code equals()}
@@ -139,20 +159,31 @@ public void setResourcesTrieRoot(GlobTrieNode<ConditionWithOrigin> resourcesTrie
139159
this.resourcesTrieRoot = resourcesTrieRoot;
140160
}
141161

142-
public EconomicMap<ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> getResourceStorage() {
143-
return resources;
162+
public void forEachResource(BiConsumer<ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> action) {
163+
MapCursor<ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> entries = resources.getEntries();
164+
while (entries.advance()) {
165+
action.accept(entries.getKey(), entries.getValue());
166+
}
167+
}
168+
169+
@Platforms(Platform.HOSTED_ONLY.class)
170+
public ConditionalRuntimeValue<ResourceStorageEntryBase> getResource(ModuleResourceKey storageKey) {
171+
return resources.get(storageKey);
144172
}
145173

174+
@Platforms(Platform.HOSTED_ONLY.class)
146175
public Iterable<ConditionalRuntimeValue<ResourceStorageEntryBase>> resources() {
147176
return resources.getValues();
148177
}
149178

179+
@Platforms(Platform.HOSTED_ONLY.class)
150180
public int count() {
151181
return resources.size();
152182
}
153183

154-
public long getLastModifiedTime() {
155-
return lastModifiedTime;
184+
public static long getLastModifiedTime() {
185+
var singletons = layeredSingletons();
186+
return singletons[singletons.length - 1].lastModifiedTime;
156187
}
157188

158189
public static String moduleName(Module module) {
@@ -169,6 +200,7 @@ public static ModuleResourceKey createStorageKey(Module module, String resourceN
169200
return new ModuleResourceKey(m, resourceName);
170201
}
171202

203+
@Platforms(Platform.HOSTED_ONLY.class)
172204
public static Set<String> getIncludedResourcesModules() {
173205
return StreamSupport.stream(singleton().resources.getKeys().spliterator(), false)
174206
.map(ModuleResourceKey::module)
@@ -320,7 +352,7 @@ private static boolean wasAlreadyInCanonicalForm(String resourceName, String can
320352
return resourceName.equals(canonicalResourceName) || removeTrailingSlash(resourceName).equals(canonicalResourceName);
321353
}
322354

323-
public ResourceStorageEntryBase getAtRuntime(String name, boolean throwOnMissing) {
355+
public static ResourceStorageEntryBase getAtRuntime(String name, boolean throwOnMissing) {
324356
return getAtRuntime(null, name, throwOnMissing);
325357
}
326358

@@ -330,29 +362,31 @@ public ResourceStorageEntryBase getAtRuntime(String name, boolean throwOnMissing
330362
* {@link MissingResourceRegistrationError}. This is needed because different modules can be
331363
* tried on the same resource name, causing an unexpected exception if we throw directly.
332364
*/
333-
public ResourceStorageEntryBase getAtRuntime(Module module, String resourceName, boolean throwOnMissing) {
365+
public static ResourceStorageEntryBase getAtRuntime(Module module, String resourceName, boolean throwOnMissing) {
334366
VMError.guarantee(ImageInfo.inImageRuntimeCode(), "This function should be used only at runtime.");
335367
String canonicalResourceName = toCanonicalForm(resourceName);
336368
String moduleName = moduleName(module);
337-
ConditionalRuntimeValue<ResourceStorageEntryBase> entry = resources.get(createStorageKey(module, canonicalResourceName));
369+
ConditionalRuntimeValue<ResourceStorageEntryBase> entry = getEntry(module, canonicalResourceName);
338370
if (entry == null) {
339371
if (MissingRegistrationUtils.throwMissingRegistrationErrors()) {
340-
MapCursor<RequestedPattern, RuntimeConditionSet> cursor = requestedPatterns.getEntries();
341-
while (cursor.advance()) {
342-
RequestedPattern moduleResourcePair = cursor.getKey();
343-
if (Objects.equals(moduleName, moduleResourcePair.module) &&
344-
((matchResource(moduleResourcePair.resource, resourceName) || matchResource(moduleResourcePair.resource, canonicalResourceName)) &&
345-
cursor.getValue().satisfied())) {
346-
return null;
372+
for (var r : layeredSingletons()) {
373+
MapCursor<RequestedPattern, RuntimeConditionSet> cursor = r.requestedPatterns.getEntries();
374+
while (cursor.advance()) {
375+
RequestedPattern moduleResourcePair = cursor.getKey();
376+
if (Objects.equals(moduleName, moduleResourcePair.module) &&
377+
((matchResource(moduleResourcePair.resource, resourceName) || matchResource(moduleResourcePair.resource, canonicalResourceName)) &&
378+
cursor.getValue().satisfied())) {
379+
return null;
380+
}
347381
}
348-
}
349382

350-
String glob = GlobUtils.transformToTriePath(resourceName, moduleName);
351-
String canonicalGlob = GlobUtils.transformToTriePath(canonicalResourceName, moduleName);
352-
GlobTrieNode<ConditionWithOrigin> globsTrie = getResourcesTrieRoot();
353-
if (CompressedGlobTrie.match(globsTrie, glob) ||
354-
CompressedGlobTrie.match(globsTrie, canonicalGlob)) {
355-
return null;
383+
String glob = GlobUtils.transformToTriePath(resourceName, moduleName);
384+
String canonicalGlob = GlobUtils.transformToTriePath(canonicalResourceName, moduleName);
385+
GlobTrieNode<ConditionWithOrigin> globsTrie = r.getResourcesTrieRoot();
386+
if (CompressedGlobTrie.match(globsTrie, glob) ||
387+
CompressedGlobTrie.match(globsTrie, canonicalGlob)) {
388+
return null;
389+
}
356390
}
357391

358392
return missingMetadata(resourceName, throwOnMissing);
@@ -389,6 +423,16 @@ public ResourceStorageEntryBase getAtRuntime(Module module, String resourceName,
389423
return unconditionalEntry;
390424
}
391425

426+
private static ConditionalRuntimeValue<ResourceStorageEntryBase> getEntry(Module module, String canonicalResourceName) {
427+
for (var r : layeredSingletons()) {
428+
ConditionalRuntimeValue<ResourceStorageEntryBase> entry = r.resources.get(createStorageKey(module, canonicalResourceName));
429+
if (entry != null) {
430+
return entry;
431+
}
432+
}
433+
return null;
434+
}
435+
392436
private static ResourceStorageEntryBase missingMetadata(String resourceName, boolean throwOnMissing) {
393437
if (throwOnMissing) {
394438
MissingResourceRegistrationUtils.missingResource(resourceName);
@@ -407,11 +451,11 @@ private static URL createURL(Module module, String resourceName, int index) {
407451
}
408452
}
409453

410-
public URL createURL(String resourceName) {
454+
public static URL createURL(String resourceName) {
411455
return createURL(null, resourceName);
412456
}
413457

414-
public URL createURL(Module module, String resourceName) {
458+
public static URL createURL(Module module, String resourceName) {
415459
if (resourceName == null) {
416460
return null;
417461
}
@@ -420,12 +464,12 @@ public URL createURL(Module module, String resourceName) {
420464
return urls.hasMoreElements() ? urls.nextElement() : null;
421465
}
422466

423-
public InputStream createInputStream(String resourceName) {
467+
public static InputStream createInputStream(String resourceName) {
424468
return createInputStream(null, resourceName);
425469
}
426470

427471
/* Avoid pulling in the URL class when only an InputStream is needed. */
428-
public InputStream createInputStream(Module module, String resourceName) {
472+
public static InputStream createInputStream(Module module, String resourceName) {
429473
if (resourceName == null) {
430474
return null;
431475
}
@@ -458,11 +502,11 @@ public InputStream createInputStream(Module module, String resourceName) {
458502
return data.isEmpty() ? null : new ByteArrayInputStream(data.get(0));
459503
}
460504

461-
public Enumeration<URL> createURLs(String resourceName) {
505+
public static Enumeration<URL> createURLs(String resourceName) {
462506
return createURLs(null, resourceName);
463507
}
464508

465-
public Enumeration<URL> createURLs(Module module, String resourceName) {
509+
public static Enumeration<URL> createURLs(Module module, String resourceName) {
466510
if (resourceName == null) {
467511
return null;
468512
}
@@ -541,6 +585,11 @@ private static boolean matchResource(String pattern, String resource) {
541585

542586
return resource.startsWith(start) && resource.endsWith(end);
543587
}
588+
589+
@Override
590+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
591+
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
592+
}
544593
}
545594

546595
@AutomaticallyRegisteredFeature

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,18 @@
3232
import java.util.Enumeration;
3333
import java.util.List;
3434

35-
import com.oracle.svm.core.util.VMError;
36-
3735
import org.graalvm.nativeimage.ImageInfo;
3836

37+
import com.oracle.svm.core.util.VMError;
38+
3939
public class ResourcesHelper {
4040

4141
public static URL nameToResourceURL(String resourceName) {
42-
return Resources.singleton().createURL(resourceName);
42+
return Resources.createURL(resourceName);
4343
}
4444

4545
public static URL nameToResourceURL(Module module, String resourceName) {
46-
return Resources.singleton().createURL(module, resourceName);
46+
return Resources.createURL(module, resourceName);
4747
}
4848

4949
public static InputStream nameToResourceInputStream(String mn, String resourceName) throws IOException {
@@ -54,7 +54,7 @@ public static InputStream nameToResourceInputStream(String mn, String resourceNa
5454
}
5555

5656
public static List<URL> nameToResourceListURLs(String resourcesName) {
57-
Enumeration<URL> urls = Resources.singleton().createURLs(resourcesName);
57+
Enumeration<URL> urls = Resources.createURLs(resourcesName);
5858
List<URL> resourceURLs = new ArrayList<>();
5959
while (urls.hasMoreElements()) {
6060
resourceURLs.add(urls.nextElement());

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

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,7 @@
8484
import java.util.concurrent.locks.ReentrantReadWriteLock;
8585
import java.util.regex.Pattern;
8686

87-
import org.graalvm.collections.MapCursor;
88-
8987
import com.oracle.svm.core.MissingRegistrationUtils;
90-
import com.oracle.svm.core.configure.ConditionalRuntimeValue;
9188
import com.oracle.svm.core.jdk.Resources;
9289
import com.oracle.svm.core.util.TimeUtils;
9390

@@ -577,7 +574,7 @@ IndexNode getInode(byte[] path) {
577574
IndexNode indexNode = inodes.get(IndexNode.keyOf(path));
578575
if (indexNode == null && MissingRegistrationUtils.throwMissingRegistrationErrors()) {
579576
// Try to access the resource to see if the metadata is present
580-
Resources.singleton().getAtRuntime(getString(path), true);
577+
Resources.getAtRuntime(getString(path), true);
581578
}
582579
return indexNode;
583580
}
@@ -658,14 +655,15 @@ private void update(Entry e) {
658655
}
659656

660657
private void readAllEntries() {
661-
MapCursor<Resources.ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> entries = Resources.singleton().getResourceStorage().getEntries();
662-
while (entries.advance()) {
663-
byte[] name = getBytes(entries.getKey().resource());
664-
ResourceStorageEntryBase entry = entries.getValue().getValue();
665-
if (entry != null && entry.hasData()) {
666-
IndexNode newIndexNode = new IndexNode(name, entry.isDirectory(), true);
667-
inodes.put(newIndexNode, newIndexNode);
668-
}
658+
for (var resources : Resources.layeredSingletons()) {
659+
resources.forEachResource((key, value) -> {
660+
byte[] name = getBytes(key.resource());
661+
ResourceStorageEntryBase entry = value.getValue();
662+
if (entry != null && entry.hasData()) {
663+
IndexNode newIndexNode = new IndexNode(name, entry.isDirectory(), true);
664+
inodes.put(newIndexNode, newIndexNode);
665+
}
666+
});
669667
}
670668
buildNodeTree();
671669
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ private NativeImageResourceFileSystemUtil() {
3636
}
3737

3838
public static byte[] getBytes(String resourceName, boolean readOnly) {
39-
Object entry = Resources.singleton().getAtRuntime(resourceName, true);
39+
Object entry = Resources.getAtRuntime(resourceName, true);
4040
if (entry == null) {
4141
return new byte[0];
4242
}
@@ -49,7 +49,7 @@ public static byte[] getBytes(String resourceName, boolean readOnly) {
4949
}
5050

5151
public static int getSize(String resourceName) {
52-
Object entry = Resources.singleton().getAtRuntime(resourceName, true);
52+
Object entry = Resources.getAtRuntime(resourceName, true);
5353
if (entry == null) {
5454
return 0;
5555
} else {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public void connect() {
7474
String resourceName = urlPath.substring(1);
7575

7676
Module module = hostNameOrNull != null ? ModuleLayer.boot().findModule(hostNameOrNull).orElse(null) : null;
77-
Object entry = Resources.singleton().getAtRuntime(module, resourceName, true);
77+
Object entry = Resources.getAtRuntime(module, resourceName, true);
7878
if (entry != null) {
7979
ResourceStorageEntry resourceStorageEntry = (ResourceStorageEntry) entry;
8080
List<byte[]> bytes = resourceStorageEntry.getData();
@@ -174,7 +174,7 @@ private void initializeHeaders() {
174174
properties.add(CONTENT_LENGTH, String.valueOf(data.length));
175175
}
176176

177-
long lastModified = Resources.singleton().getLastModifiedTime();
177+
long lastModified = Resources.getLastModifiedTime();
178178
Date date = new Date(lastModified);
179179
SimpleDateFormat fo = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
180180
fo.setTimeZone(TimeZone.getTimeZone("GMT"));

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,9 @@
3333
import java.util.List;
3434
import java.util.concurrent.ConcurrentHashMap;
3535

36-
import org.graalvm.collections.EconomicMap;
3736
import org.graalvm.nativeimage.Platform;
3837
import org.graalvm.nativeimage.Platforms;
3938

40-
import com.oracle.svm.core.configure.ConditionalRuntimeValue;
4139
import com.oracle.svm.core.jdk.Resources;
4240
import com.oracle.svm.core.jdk.resources.ResourceStorageEntryBase;
4341
import com.oracle.svm.core.util.VMError;
@@ -101,12 +99,11 @@ private static List<ResourceReportEntry> getResourceReportEntryList(ConcurrentHa
10199
}
102100

103101
List<ResourceReportEntry> resourceInfoList = new ArrayList<>();
104-
EconomicMap<Resources.ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> resourceStorage = Resources.singleton().getResourceStorage();
105-
resourceStorage.getKeys().forEach(key -> {
102+
Resources.singleton().forEachResource((key, value) -> {
106103
Module module = key.module();
107104
String resourceName = key.resource();
108105

109-
ResourceStorageEntryBase storageEntry = resourceStorage.get(key).getValueUnconditionally();
106+
ResourceStorageEntryBase storageEntry = value.getValueUnconditionally();
110107
List<SourceAndOrigin> registeredEntrySources = collection.get(key);
111108

112109
if (registeredEntrySources == null && storageEntry != NEGATIVE_QUERY_MARKER) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public void addGlob(ConfigurationCondition condition, String module, String glob
199199

200200
@Override
201201
public void addCondition(ConfigurationCondition condition, Module module, String resourcePath) {
202-
var conditionalResource = Resources.singleton().getResourceStorage().get(createStorageKey(module, resourcePath));
202+
var conditionalResource = Resources.singleton().getResource(createStorageKey(module, resourcePath));
203203
if (conditionalResource != null) {
204204
classInitializationSupport.addForTypeReachedTracking(condition.getType());
205205
conditionalResource.getConditions().addCondition(condition);

0 commit comments

Comments
 (0)