Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,13 @@ public static void registerClass(Class<?> clazz) {
return; // must be defined at runtime before it can be looked up
}
String name = clazz.getName();
if (!singleton().knownClasses.containsKey(name) || !(singleton().knownClasses.get(name) instanceof Throwable)) {
/*
* If the class has already been seen as throwing an error, we don't overwrite this
* error
*/
VMError.guarantee(!singleton().knownClasses.containsKey(name) || singleton().knownClasses.get(name) == clazz);
singleton().knownClasses.put(name, clazz);
}
Object currentValue = singleton().knownClasses.get(name);
VMError.guarantee(currentValue == null || currentValue == clazz || currentValue instanceof Throwable,
"Invalid Class.forName value for %s: %s", name, currentValue);
/*
* If the class has already been seen as throwing an error, we don't overwrite this error
*/
singleton().knownClasses.putIfAbsent(name, clazz);
}

@Platforms(Platform.HOSTED_ONLY.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public class BundleContentSubstitutedLocalizationSupport extends LocalizationSup

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

private final Set<String> existingBundles = ConcurrentHashMap.newKeySet();

public BundleContentSubstitutedLocalizationSupport(Locale defaultLocale, Set<Locale> locales, Charset defaultCharset, List<String> requestedPatterns, ForkJoinPool pool) {
super(defaultLocale, locales, defaultCharset);
this.pool = pool;
Expand Down Expand Up @@ -163,4 +165,23 @@ public boolean shouldCompressBundle(ResourceBundle bundle) {
public void prepareNonCompliant(Class<?> clazz) throws ReflectiveOperationException {
storedBundles.put(clazz, new DelayedBundle(clazz));
}

@Override
public boolean isNotIncluded(String bundleName) {
return !existingBundles.contains(bundleName);
}

@Override
public void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) {
super.prepareBundle(bundleName, bundle, locale);
/* Initialize ResourceBundle.keySet eagerly */
bundle.keySet();
this.existingBundles.add(control.toBundleName(bundleName, locale));
}

@Override
public void prepareClassResourceBundle(String basename, Class<?> bundleClass) {
super.prepareClassResourceBundle(basename, bundleClass);
this.existingBundles.add(bundleClass.getName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
package com.oracle.svm.core.jdk.localization;

import java.nio.charset.Charset;
import java.util.Collection;
import java.util.HashMap;
import java.util.IllformedLocaleException;
import java.util.Locale;
Expand All @@ -41,6 +42,7 @@
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.hosted.RuntimeReflection;
import org.graalvm.nativeimage.impl.ConfigurationCondition;
import org.graalvm.nativeimage.impl.RuntimeReflectionSupport;
import org.graalvm.nativeimage.impl.RuntimeResourceSupport;

import com.oracle.svm.core.SubstrateUtil;
Expand Down Expand Up @@ -107,6 +109,7 @@ public void prepareBundle(String bundleName, ResourceBundle bundle, Locale local
}
ImageSingletons.lookup(RuntimeResourceSupport.class).addResources(ConfigurationCondition.alwaysTrue(), resultingPattern + "\\.properties");
} else {
registerRequiredReflectionForBundle(bundleName, Set.of(locale));
RuntimeReflection.register(bundle.getClass());
RuntimeReflection.registerForReflectiveInstantiation(bundle.getClass());
onBundlePrepared(bundle);
Expand All @@ -128,6 +131,28 @@ private String getBundleName(String fixedBundleName, Locale locale) {
}
}

public void registerRequiredReflectionForBundle(String baseName, Collection<Locale> wantedLocales) {
int i = baseName.lastIndexOf('.');
if (i > 0) {
String name = baseName.substring(i + 1) + "Provider";
String providerName = baseName.substring(0, i) + ".spi." + name;
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerClassLookup(ConfigurationCondition.alwaysTrue(), providerName);
}

ImageSingletons.lookup(RuntimeReflectionSupport.class).registerClassLookup(ConfigurationCondition.alwaysTrue(), baseName);

for (Locale locale : wantedLocales) {
registerRequiredReflectionForBundleAndLocale(baseName, locale);
}
}

private void registerRequiredReflectionForBundleAndLocale(String baseName, Locale baseLocale) {
for (Locale locale : control.getCandidateLocales(baseName, baseLocale)) {
String bundleWithLocale = control.toBundleName(baseName, locale);
RuntimeReflection.registerClassLookup(bundleWithLocale);
}
}

/**
* Template method for subclasses to perform additional tasks.
*/
Expand All @@ -153,6 +178,11 @@ public void prepareNonCompliant(Class<?> clazz) throws ReflectiveOperationExcept
/*- By default, there is nothing to do */
}

@SuppressWarnings("unused")
public boolean isNotIncluded(String bundleName) {
return false;
}

/**
* @return locale for given tag or null for invalid ones
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,18 @@
*/
package com.oracle.svm.core.jdk.localization.substitutions;

import java.io.IOException;
import java.util.Locale;
import java.util.ResourceBundle;

import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.jdk.localization.LocalizationSupport;

import java.util.Locale;
import java.util.ResourceBundle;
import sun.util.resources.Bundles;

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

return false;
}

@Substitute
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
/*
* Legacy mechanism to locate resource bundle in unnamed module only that is visible to the
* given loader and accessible to the given caller.
*/
String bundleName = toBundleName(baseName, locale);
if (format.equals("java.class") && ImageSingletons.lookup(LocalizationSupport.class).isNotIncluded(bundleName)) {
return null;
}
var bundle = newBundle0(bundleName, format, loader, reload);
if (bundle == null) {
// Try loading legacy ISO language's other bundles
var otherBundleName = Bundles.toOtherBundleName(baseName, bundleName, locale);
if (!bundleName.equals(otherBundleName)) {
bundle = newBundle0(otherBundleName, format, loader, reload);
}
}

return bundle;
}

@Alias
public native String toBundleName(String baseName, Locale locale);

@Alias
private native ResourceBundle newBundle0(String bundleName, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ public static void forField(Class<?> declaringClass, String fieldName) {

public static void forMethod(Class<?> declaringClass, String methodName, Class<?>[] paramTypes) {
StringJoiner paramTypeNames = new StringJoiner(", ", "(", ")");
for (Class<?> paramType : paramTypes) {
paramTypeNames.add(paramType.getTypeName());
if (paramTypes != null) {
for (Class<?> paramType : paramTypes) {
paramTypeNames.add(paramType.getTypeName());
}
}
MissingReflectionRegistrationError exception = new MissingReflectionRegistrationError(errorMessage("access method",
declaringClass.getTypeName() + "#" + methodName + paramTypeNames),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ void handleServiceClassIsReachable(DuringAnalysisAccess access, Class<?> service
if (nullaryConstructor != null) {
RuntimeReflection.register(providerClass);
RuntimeReflection.register(nullaryConstructor);
RuntimeReflection.registerAllDeclaredMethods(providerClass);
registeredProviders.add(provider);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.impl.ConfigurationCondition;
import org.graalvm.nativeimage.impl.RuntimeReflectionSupport;
import org.graalvm.nativeimage.hosted.RuntimeReflection;

import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
Expand All @@ -41,12 +39,10 @@
@AutomaticallyRegisteredFeature
public class AnnotationFeature implements InternalFeature {

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

@Override
public void duringSetup(DuringSetupAccess access) {
runtimeReflectionSupport = ImageSingletons.lookup(RuntimeReflectionSupport.class);
access.registerObjectReplacer(this::registerDeclaredMethods);
}

Expand All @@ -62,7 +58,7 @@ private Object registerDeclaredMethods(Object obj) {
if (obj instanceof Annotation annotation && Proxy.isProxyClass(annotation.getClass())) {
Class<? extends Annotation> annotationType = annotation.annotationType();
if (processedTypes.add(annotationType)) {
runtimeReflectionSupport.registerAllDeclaredMethodsQuery(ConfigurationCondition.alwaysTrue(), false, annotationType);
RuntimeReflection.registerAllDeclaredMethods(annotationType);
}
}
return obj;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ public void prepareClassResourceBundle(String basename, String className) {
Class<?> bundleClass = findClassByName.apply(className);
UserError.guarantee(ResourceBundle.class.isAssignableFrom(bundleClass), "%s is not a subclass of ResourceBundle", bundleClass.getName());
trace("Adding class based resource bundle: " + className + " " + bundleClass);
support.registerRequiredReflectionForBundle(basename, Set.of());
support.prepareClassResourceBundle(basename, bundleClass);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public void registerClassLookupException(ConfigurationCondition condition, Strin
public void registerClassLookup(ConfigurationCondition condition, String typeName) {
checkNotSealed();
try {
register(condition, Class.forName(typeName, false, null));
register(condition, Class.forName(typeName, false, ClassLoader.getSystemClassLoader()));
} catch (ClassNotFoundException e) {
registerConditionalConfiguration(condition, () -> ClassForNameSupport.registerNegativeQuery(typeName));
} catch (Throwable t) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ private static void initializeScalaEnumerations(BeforeAnalysisAccess beforeAnaly

access.findSubclasses(scalaEnum).forEach(enumClass -> {
/* this is based on implementation of scala.Enumeration.populateNamesMap */
RuntimeReflection.register(enumClass.getDeclaredFields());
RuntimeReflection.registerAllDeclaredFields(enumClass);
// all method relevant for Enums
Method[] relevantMethods = Arrays.stream(enumClass.getDeclaredMethods())
.filter(m -> m.getParameterTypes().length == 0 &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void duringSetup(final DuringSetupAccess access) {
// register the service implementation for reflection explicitly,
// non-standard services are not processed automatically
RuntimeReflection.register(NoOpImpl.class);
RuntimeReflection.register(NoOpImpl.class.getConstructors());
RuntimeReflection.register(NoOpImpl.class.getDeclaredConstructors());
}
}

Expand Down