Skip to content

Commit 9faf13e

Browse files
committed
[GR-46823] Bugfixes for missing registration errors
PullRequest: graal/14888
2 parents 469295a + 11f7735 commit 9faf13e

File tree

12 files changed

+132
-128
lines changed

12 files changed

+132
-128
lines changed

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java

Lines changed: 24 additions & 107 deletions
Large diffs are not rendered by default.

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,13 @@ public static void registerClass(Class<?> clazz) {
5555
return; // must be defined at runtime before it can be looked up
5656
}
5757
String name = clazz.getName();
58-
if (!singleton().knownClasses.containsKey(name) || !(singleton().knownClasses.get(name) instanceof Throwable)) {
59-
/*
60-
* If the class has already been seen as throwing an error, we don't overwrite this
61-
* error
62-
*/
63-
VMError.guarantee(!singleton().knownClasses.containsKey(name) || singleton().knownClasses.get(name) == clazz);
64-
singleton().knownClasses.put(name, clazz);
65-
}
58+
Object currentValue = singleton().knownClasses.get(name);
59+
VMError.guarantee(currentValue == null || currentValue == clazz || currentValue instanceof Throwable,
60+
"Invalid Class.forName value for %s: %s", name, currentValue);
61+
/*
62+
* If the class has already been seen as throwing an error, we don't overwrite this error
63+
*/
64+
singleton().knownClasses.putIfAbsent(name, clazz);
6665
}
6766

6867
@Platforms(Platform.HOSTED_ONLY.class)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public class BundleContentSubstitutedLocalizationSupport extends LocalizationSup
6565

6666
private final Map<Class<?>, StoredBundle> storedBundles = new ConcurrentHashMap<>();
6767

68+
private final Set<String> existingBundles = ConcurrentHashMap.newKeySet();
69+
6870
public BundleContentSubstitutedLocalizationSupport(Locale defaultLocale, Set<Locale> locales, Charset defaultCharset, List<String> requestedPatterns, ForkJoinPool pool) {
6971
super(defaultLocale, locales, defaultCharset);
7072
this.pool = pool;
@@ -163,4 +165,23 @@ public boolean shouldCompressBundle(ResourceBundle bundle) {
163165
public void prepareNonCompliant(Class<?> clazz) throws ReflectiveOperationException {
164166
storedBundles.put(clazz, new DelayedBundle(clazz));
165167
}
168+
169+
@Override
170+
public boolean isNotIncluded(String bundleName) {
171+
return !existingBundles.contains(bundleName);
172+
}
173+
174+
@Override
175+
public void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) {
176+
super.prepareBundle(bundleName, bundle, locale);
177+
/* Initialize ResourceBundle.keySet eagerly */
178+
bundle.keySet();
179+
this.existingBundles.add(control.toBundleName(bundleName, locale));
180+
}
181+
182+
@Override
183+
public void prepareClassResourceBundle(String basename, Class<?> bundleClass) {
184+
super.prepareClassResourceBundle(basename, bundleClass);
185+
this.existingBundles.add(bundleClass.getName());
186+
}
166187
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package com.oracle.svm.core.jdk.localization;
2727

2828
import java.nio.charset.Charset;
29+
import java.util.Collection;
2930
import java.util.HashMap;
3031
import java.util.IllformedLocaleException;
3132
import java.util.Locale;
@@ -41,6 +42,7 @@
4142
import org.graalvm.nativeimage.Platforms;
4243
import org.graalvm.nativeimage.hosted.RuntimeReflection;
4344
import org.graalvm.nativeimage.impl.ConfigurationCondition;
45+
import org.graalvm.nativeimage.impl.RuntimeReflectionSupport;
4446
import org.graalvm.nativeimage.impl.RuntimeResourceSupport;
4547

4648
import com.oracle.svm.core.SubstrateUtil;
@@ -107,6 +109,7 @@ public void prepareBundle(String bundleName, ResourceBundle bundle, Locale local
107109
}
108110
ImageSingletons.lookup(RuntimeResourceSupport.class).addResources(ConfigurationCondition.alwaysTrue(), resultingPattern + "\\.properties");
109111
} else {
112+
registerRequiredReflectionForBundle(bundleName, Set.of(locale));
110113
RuntimeReflection.register(bundle.getClass());
111114
RuntimeReflection.registerForReflectiveInstantiation(bundle.getClass());
112115
onBundlePrepared(bundle);
@@ -128,6 +131,28 @@ private String getBundleName(String fixedBundleName, Locale locale) {
128131
}
129132
}
130133

134+
public void registerRequiredReflectionForBundle(String baseName, Collection<Locale> wantedLocales) {
135+
int i = baseName.lastIndexOf('.');
136+
if (i > 0) {
137+
String name = baseName.substring(i + 1) + "Provider";
138+
String providerName = baseName.substring(0, i) + ".spi." + name;
139+
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerClassLookup(ConfigurationCondition.alwaysTrue(), providerName);
140+
}
141+
142+
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerClassLookup(ConfigurationCondition.alwaysTrue(), baseName);
143+
144+
for (Locale locale : wantedLocales) {
145+
registerRequiredReflectionForBundleAndLocale(baseName, locale);
146+
}
147+
}
148+
149+
private void registerRequiredReflectionForBundleAndLocale(String baseName, Locale baseLocale) {
150+
for (Locale locale : control.getCandidateLocales(baseName, baseLocale)) {
151+
String bundleWithLocale = control.toBundleName(baseName, locale);
152+
RuntimeReflection.registerClassLookup(bundleWithLocale);
153+
}
154+
}
155+
131156
/**
132157
* Template method for subclasses to perform additional tasks.
133158
*/
@@ -153,6 +178,11 @@ public void prepareNonCompliant(Class<?> clazz) throws ReflectiveOperationExcept
153178
/*- By default, there is nothing to do */
154179
}
155180

181+
@SuppressWarnings("unused")
182+
public boolean isNotIncluded(String bundleName) {
183+
return false;
184+
}
185+
156186
/**
157187
* @return locale for given tag or null for invalid ones
158188
*/

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_util_ResourceBundle_Control.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,18 @@
2424
*/
2525
package com.oracle.svm.core.jdk.localization.substitutions;
2626

27+
import java.io.IOException;
28+
import java.util.Locale;
29+
import java.util.ResourceBundle;
30+
31+
import org.graalvm.nativeimage.ImageSingletons;
32+
33+
import com.oracle.svm.core.annotate.Alias;
2734
import com.oracle.svm.core.annotate.Substitute;
2835
import com.oracle.svm.core.annotate.TargetClass;
36+
import com.oracle.svm.core.jdk.localization.LocalizationSupport;
2937

30-
import java.util.Locale;
31-
import java.util.ResourceBundle;
38+
import sun.util.resources.Bundles;
3239

3340
@TargetClass(value = java.util.ResourceBundle.class, innerClass = "Control")
3441
@SuppressWarnings({"unused", "static-method"})
@@ -45,4 +52,34 @@ public boolean needsReload(String baseName, Locale locale,
4552

4653
return false;
4754
}
55+
56+
@Substitute
57+
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
58+
throws IllegalAccessException, InstantiationException, IOException {
59+
/*
60+
* Legacy mechanism to locate resource bundle in unnamed module only that is visible to the
61+
* given loader and accessible to the given caller.
62+
*/
63+
String bundleName = toBundleName(baseName, locale);
64+
if (format.equals("java.class") && ImageSingletons.lookup(LocalizationSupport.class).isNotIncluded(bundleName)) {
65+
return null;
66+
}
67+
var bundle = newBundle0(bundleName, format, loader, reload);
68+
if (bundle == null) {
69+
// Try loading legacy ISO language's other bundles
70+
var otherBundleName = Bundles.toOtherBundleName(baseName, bundleName, locale);
71+
if (!bundleName.equals(otherBundleName)) {
72+
bundle = newBundle0(otherBundleName, format, loader, reload);
73+
}
74+
}
75+
76+
return bundle;
77+
}
78+
79+
@Alias
80+
public native String toBundleName(String baseName, Locale locale);
81+
82+
@Alias
83+
private native ResourceBundle newBundle0(String bundleName, String format, ClassLoader loader, boolean reload)
84+
throws IllegalAccessException, InstantiationException, IOException;
4885
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/MissingReflectionRegistrationUtils.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ public static void forField(Class<?> declaringClass, String fieldName) {
5656

5757
public static void forMethod(Class<?> declaringClass, String methodName, Class<?>[] paramTypes) {
5858
StringJoiner paramTypeNames = new StringJoiner(", ", "(", ")");
59-
for (Class<?> paramType : paramTypes) {
60-
paramTypeNames.add(paramType.getTypeName());
59+
if (paramTypes != null) {
60+
for (Class<?> paramType : paramTypes) {
61+
paramTypeNames.add(paramType.getTypeName());
62+
}
6163
}
6264
MissingReflectionRegistrationError exception = new MissingReflectionRegistrationError(errorMessage("access method",
6365
declaringClass.getTypeName() + "#" + methodName + paramTypeNames),

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ void handleServiceClassIsReachable(DuringAnalysisAccess access, Class<?> service
178178
if (nullaryConstructor != null) {
179179
RuntimeReflection.register(providerClass);
180180
RuntimeReflection.register(nullaryConstructor);
181+
RuntimeReflection.registerAllDeclaredMethods(providerClass);
181182
registeredProviders.add(provider);
182183
}
183184
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationFeature.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@
3030
import java.util.Set;
3131
import java.util.concurrent.ConcurrentHashMap;
3232

33-
import org.graalvm.nativeimage.ImageSingletons;
34-
import org.graalvm.nativeimage.impl.ConfigurationCondition;
35-
import org.graalvm.nativeimage.impl.RuntimeReflectionSupport;
33+
import org.graalvm.nativeimage.hosted.RuntimeReflection;
3634

3735
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3836
import com.oracle.svm.core.feature.InternalFeature;
@@ -41,12 +39,10 @@
4139
@AutomaticallyRegisteredFeature
4240
public class AnnotationFeature implements InternalFeature {
4341

44-
private RuntimeReflectionSupport runtimeReflectionSupport;
4542
private final Set<Class<? extends Annotation>> processedTypes = ConcurrentHashMap.newKeySet();
4643

4744
@Override
4845
public void duringSetup(DuringSetupAccess access) {
49-
runtimeReflectionSupport = ImageSingletons.lookup(RuntimeReflectionSupport.class);
5046
access.registerObjectReplacer(this::registerDeclaredMethods);
5147
}
5248

@@ -62,7 +58,7 @@ private Object registerDeclaredMethods(Object obj) {
6258
if (obj instanceof Annotation annotation && Proxy.isProxyClass(annotation.getClass())) {
6359
Class<? extends Annotation> annotationType = annotation.annotationType();
6460
if (processedTypes.add(annotationType)) {
65-
runtimeReflectionSupport.registerAllDeclaredMethodsQuery(ConfigurationCondition.alwaysTrue(), false, annotationType);
61+
RuntimeReflection.registerAllDeclaredMethods(annotationType);
6662
}
6763
}
6864
return obj;

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ public void prepareClassResourceBundle(String basename, String className) {
546546
Class<?> bundleClass = findClassByName.apply(className);
547547
UserError.guarantee(ResourceBundle.class.isAssignableFrom(bundleClass), "%s is not a subclass of ResourceBundle", bundleClass.getName());
548548
trace("Adding class based resource bundle: " + className + " " + bundleClass);
549+
support.registerRequiredReflectionForBundle(basename, Set.of());
549550
support.prepareClassResourceBundle(basename, bundleClass);
550551
}
551552

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ public void registerClassLookupException(ConfigurationCondition condition, Strin
225225
public void registerClassLookup(ConfigurationCondition condition, String typeName) {
226226
checkNotSealed();
227227
try {
228-
register(condition, Class.forName(typeName, false, null));
228+
register(condition, Class.forName(typeName, false, ClassLoader.getSystemClassLoader()));
229229
} catch (ClassNotFoundException e) {
230230
registerConditionalConfiguration(condition, () -> ClassForNameSupport.registerNegativeQuery(typeName));
231231
} catch (Throwable t) {

0 commit comments

Comments
 (0)