4747import org .graalvm .nativeimage .ImageSingletons ;
4848import org .graalvm .nativeimage .Platform ;
4949import org .graalvm .nativeimage .Platforms ;
50+ import org .graalvm .nativeimage .impl .ConfigurationCondition ;
5051
5152import com .oracle .svm .core .BuildPhaseProvider ;
5253import com .oracle .svm .core .MissingRegistrationUtils ;
5354import com .oracle .svm .core .SubstrateOptions ;
55+ import com .oracle .svm .core .configure .ConditionalRuntimeValue ;
56+ import com .oracle .svm .core .configure .RuntimeConditionSet ;
5457import com .oracle .svm .core .feature .AutomaticallyRegisteredFeature ;
5558import com .oracle .svm .core .feature .InternalFeature ;
5659import com .oracle .svm .core .jdk .resources .MissingResourceRegistrationError ;
@@ -90,8 +93,8 @@ public static Resources singleton() {
9093 * ends up in the image heap is computed after the runtime module instances have been computed
9194 * {see com.oracle.svm.hosted.ModuleLayerFeature}.
9295 */
93- private final EconomicMap <ModuleResourceKey , ResourceStorageEntryBase > resources = ImageHeapMap .create ();
94- private final EconomicMap <RequestedPattern , Boolean > requestedPatterns = ImageHeapMap .create ();
96+ private final EconomicMap <ModuleResourceKey , ConditionalRuntimeValue < ResourceStorageEntryBase > > resources = ImageHeapMap .create ();
97+ private final EconomicMap <RequestedPattern , RuntimeConditionSet > requestedPatterns = ImageHeapMap .create ();
9598
9699 public record RequestedPattern (String module , String resource ) {
97100 }
@@ -108,9 +111,9 @@ public record ModuleResourceKey(Module module, String resource) {
108111
109112 /**
110113 * The object used to detect that the resource is not reachable according to the metadata. It
111- * can be returned by the {@link Resources#get } method if the resource was not correctly
112- * specified in the configuration, but we do not want to throw directly (for example when we try
113- * to check all the modules for a resource).
114+ * can be returned by the {@link Resources#getAtRuntime } method if the resource was not
115+ * correctly specified in the configuration, but we do not want to throw directly (for example
116+ * when we try to check all the modules for a resource).
114117 */
115118 private static final ResourceStorageEntryBase MISSING_METADATA_MARKER = new ResourceStorageEntryBase ();
116119
@@ -124,11 +127,11 @@ public record ModuleResourceKey(Module module, String resource) {
124127 Resources () {
125128 }
126129
127- public EconomicMap <ModuleResourceKey , ResourceStorageEntryBase > getResourceStorage () {
130+ public EconomicMap <ModuleResourceKey , ConditionalRuntimeValue < ResourceStorageEntryBase > > getResourceStorage () {
128131 return resources ;
129132 }
130133
131- public Iterable <ResourceStorageEntryBase > resources () {
134+ public Iterable <ConditionalRuntimeValue < ResourceStorageEntryBase > > resources () {
132135 return resources .getValues ();
133136 }
134137
@@ -182,17 +185,18 @@ private void addEntry(Module module, String resourceName, boolean isDirectory, b
182185 Module m = module != null && module .isNamed () ? module : null ;
183186 synchronized (resources ) {
184187 ModuleResourceKey key = createStorageKey (m , resourceName );
185- ResourceStorageEntryBase entry = resources .get (key );
188+ RuntimeConditionSet conditionSet = RuntimeConditionSet .emptySet ();
189+ ConditionalRuntimeValue <ResourceStorageEntryBase > entry = resources .get (key );
186190 if (isNegativeQuery ) {
187191 if (entry == null ) {
188- resources .put (key , NEGATIVE_QUERY_MARKER );
192+ resources .put (key , new ConditionalRuntimeValue <>( conditionSet , NEGATIVE_QUERY_MARKER ) );
189193 }
190194 return ;
191195 }
192196
193- if (entry == null || entry == NEGATIVE_QUERY_MARKER ) {
197+ if (entry == null || entry . getValueUnconditionally () == NEGATIVE_QUERY_MARKER ) {
194198 updateTimeStamp ();
195- entry = new ResourceStorageEntry (isDirectory , fromJar );
199+ entry = new ConditionalRuntimeValue <>( conditionSet , new ResourceStorageEntry (isDirectory , fromJar ) );
196200 resources .put (key , entry );
197201 } else {
198202 if (key .module () != null ) {
@@ -201,8 +205,7 @@ private void addEntry(Module module, String resourceName, boolean isDirectory, b
201205 return ;
202206 }
203207 }
204-
205- entry .addData (data );
208+ entry .getValueUnconditionally ().addData (data );
206209 }
207210 }
208211
@@ -243,7 +246,7 @@ public void registerIOException(Module module, String resourceName, IOException
243246 ModuleResourceKey key = createStorageKey (module , resourceName );
244247 synchronized (resources ) {
245248 updateTimeStamp ();
246- resources .put (key , new ResourceExceptionEntry (e ));
249+ resources .put (key , new ConditionalRuntimeValue <>( RuntimeConditionSet . emptySet (), new ResourceExceptionEntry (e ) ));
247250 }
248251 }
249252
@@ -258,16 +261,11 @@ public void registerNegativeQuery(Module module, String resourceName) {
258261 }
259262
260263 @ Platforms (Platform .HOSTED_ONLY .class )
261- public void registerIncludePattern (String pattern ) {
262- registerIncludePattern (null , pattern );
263- }
264-
265- @ Platforms (Platform .HOSTED_ONLY .class )
266- public void registerIncludePattern (String module , String pattern ) {
264+ public void registerIncludePattern (ConfigurationCondition condition , String module , String pattern ) {
267265 assert MissingRegistrationUtils .throwMissingRegistrationErrors ();
268266 synchronized (requestedPatterns ) {
269267 updateTimeStamp ();
270- requestedPatterns .put (new RequestedPattern (module , handleEscapedCharacters (pattern )), Boolean . TRUE );
268+ requestedPatterns .put (new RequestedPattern (module , handleEscapedCharacters (pattern )), RuntimeConditionSet . createHosted ( condition ) );
271269 }
272270 }
273271
@@ -310,8 +308,8 @@ private static boolean wasAlreadyInCanonicalForm(String resourceName, String can
310308 return resourceName .equals (canonicalResourceName ) || removeTrailingSlash (resourceName ).equals (canonicalResourceName );
311309 }
312310
313- public ResourceStorageEntryBase get (String name , boolean throwOnMissing ) {
314- return get (null , name , throwOnMissing );
311+ public ResourceStorageEntryBase getAtRuntime (String name , boolean throwOnMissing ) {
312+ return getAtRuntime (null , name , throwOnMissing );
315313 }
316314
317315 /**
@@ -320,17 +318,18 @@ public ResourceStorageEntryBase get(String name, boolean throwOnMissing) {
320318 * {@link MissingResourceRegistrationError}. This is needed because different modules can be
321319 * tried on the same resource name, causing an unexpected exception if we throw directly.
322320 */
323- public ResourceStorageEntryBase get (Module module , String resourceName , boolean throwOnMissing ) {
321+ public ResourceStorageEntryBase getAtRuntime (Module module , String resourceName , boolean throwOnMissing ) {
324322 String canonicalResourceName = toCanonicalForm (resourceName );
325323 String moduleName = moduleName (module );
326- ResourceStorageEntryBase entry = resources .get (createStorageKey (module , canonicalResourceName ));
324+ ConditionalRuntimeValue < ResourceStorageEntryBase > entry = resources .get (createStorageKey (module , canonicalResourceName ));
327325 if (entry == null ) {
328326 if (MissingRegistrationUtils .throwMissingRegistrationErrors ()) {
329- MapCursor <RequestedPattern , Boolean > cursor = requestedPatterns .getEntries ();
327+ MapCursor <RequestedPattern , RuntimeConditionSet > cursor = requestedPatterns .getEntries ();
330328 while (cursor .advance ()) {
331329 RequestedPattern moduleResourcePair = cursor .getKey ();
332330 if (Objects .equals (moduleName , moduleResourcePair .module ) &&
333- (matchResource (moduleResourcePair .resource , resourceName ) || matchResource (moduleResourcePair .resource , canonicalResourceName ))) {
331+ ((matchResource (moduleResourcePair .resource , resourceName ) || matchResource (moduleResourcePair .resource , canonicalResourceName )) &&
332+ cursor .getValue ().satisfied ())) {
334333 return null ;
335334 }
336335 }
@@ -348,27 +347,33 @@ public ResourceStorageEntryBase get(Module module, String resourceName, boolean
348347 return null ;
349348 }
350349 }
351- if (entry .isException ()) {
352- throw new RuntimeException (entry .getException ());
350+ if (!entry .getConditions ().satisfied ()) {
351+ return missingMetadata (resourceName , throwOnMissing );
352+ }
353+
354+ ResourceStorageEntryBase unconditionalEntry = entry .getValue ();
355+ assert unconditionalEntry != null : "Already checked above that the condition is satisfied" ;
356+ if (unconditionalEntry .isException ()) {
357+ throw new RuntimeException (unconditionalEntry .getException ());
353358 }
354- if (entry == NEGATIVE_QUERY_MARKER ) {
359+ if (unconditionalEntry == NEGATIVE_QUERY_MARKER ) {
355360 return null ;
356361 }
357- if (entry .isFromJar () && !wasAlreadyInCanonicalForm (resourceName , canonicalResourceName )) {
362+ if (unconditionalEntry .isFromJar () && !wasAlreadyInCanonicalForm (resourceName , canonicalResourceName )) {
358363 /*
359364 * The resource originally came from a jar file, thus behave like ZipFileSystem behaves
360365 * for non-canonical paths.
361366 */
362367 return null ;
363368 }
364- if (!entry .isDirectory () && hasTrailingSlash (resourceName )) {
369+ if (!unconditionalEntry .isDirectory () && hasTrailingSlash (resourceName )) {
365370 /*
366371 * If this is an actual resource file (not a directory) we do not tolerate a trailing
367372 * slash.
368373 */
369374 return null ;
370375 }
371- return entry ;
376+ return unconditionalEntry ;
372377 }
373378
374379 private static ResourceStorageEntryBase missingMetadata (String resourceName , boolean throwOnMissing ) {
@@ -412,15 +417,15 @@ public InputStream createInputStream(Module module, String resourceName) {
412417 return null ;
413418 }
414419
415- ResourceStorageEntryBase entry = get (module , resourceName , false );
420+ ResourceStorageEntryBase entry = getAtRuntime (module , resourceName , false );
416421 boolean isInMetadata = entry != MISSING_METADATA_MARKER ;
417422 if (moduleName (module ) == null && (entry == MISSING_METADATA_MARKER || entry == null )) {
418423 /*
419424 * If module is not specified or is an unnamed module and entry was not found as
420425 * classpath-resource we have to search for the resource in all modules in the image.
421426 */
422427 for (Module m : RuntimeModuleSupport .instance ().getBootLayer ().modules ()) {
423- entry = get (m , resourceName , false );
428+ entry = getAtRuntime (m , resourceName , false );
424429 if (entry != MISSING_METADATA_MARKER ) {
425430 isInMetadata = true ;
426431 }
@@ -458,15 +463,15 @@ public Enumeration<URL> createURLs(Module module, String resourceName) {
458463 /* If moduleName was unspecified we have to consider all modules in the image */
459464 if (moduleName (module ) == null ) {
460465 for (Module m : RuntimeModuleSupport .instance ().getBootLayer ().modules ()) {
461- ResourceStorageEntryBase entry = get (m , resourceName , false );
466+ ResourceStorageEntryBase entry = getAtRuntime (m , resourceName , false );
462467 if (entry == MISSING_METADATA_MARKER ) {
463468 continue ;
464469 }
465470 missingMetadata = false ;
466471 addURLEntries (resourcesURLs , (ResourceStorageEntry ) entry , m , shouldAppendTrailingSlash ? canonicalResourceName + '/' : canonicalResourceName );
467472 }
468473 }
469- ResourceStorageEntryBase explicitEntry = get (module , resourceName , false );
474+ ResourceStorageEntryBase explicitEntry = getAtRuntime (module , resourceName , false );
470475 if (explicitEntry != MISSING_METADATA_MARKER ) {
471476 missingMetadata = false ;
472477 addURLEntries (resourcesURLs , (ResourceStorageEntry ) explicitEntry , module , shouldAppendTrailingSlash ? canonicalResourceName + '/' : canonicalResourceName );
@@ -540,9 +545,10 @@ public void afterCompilation(AfterCompilationAccess access) {
540545 * of lazily initialized fields. Only the byte[] arrays themselves can be safely made
541546 * read-only.
542547 */
543- for (ResourceStorageEntryBase entry : Resources .singleton ().resources ()) {
544- if (entry .hasData ()) {
545- for (byte [] resource : entry .getData ()) {
548+ for (ConditionalRuntimeValue <ResourceStorageEntryBase > entry : Resources .singleton ().resources ()) {
549+ var unconditionalEntry = entry .getValueUnconditionally ();
550+ if (unconditionalEntry .hasData ()) {
551+ for (byte [] resource : unconditionalEntry .getData ()) {
546552 access .registerAsImmutable (resource );
547553 }
548554 }
0 commit comments