Skip to content

Commit

Permalink
WIP, make spring petclinic work
Browse files Browse the repository at this point in the history
  • Loading branch information
vjovanov committed Dec 9, 2024
1 parent abb9e56 commit 1fcdae6
Show file tree
Hide file tree
Showing 21 changed files with 146 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public static void registerAllDeclaredMethods(Class<?> declaringClass) {
* @since 23.0
*/
public static void registerAllConstructors(Class<?> declaringClass) {
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerAllConstructorsQuery(ConfigurationCondition.alwaysTrue(), true, declaringClass);
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerAllConstructorsQuery(ConfigurationCondition.alwaysTrue(), false, declaringClass);
}

/**
Expand All @@ -211,7 +211,7 @@ public static void registerAllConstructors(Class<?> declaringClass) {
* @since 23.0
*/
public static void registerAllDeclaredConstructors(Class<?> declaringClass) {
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerAllDeclaredConstructorsQuery(ConfigurationCondition.alwaysTrue(), true, declaringClass);
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerAllDeclaredConstructorsQuery(ConfigurationCondition.alwaysTrue(), false, declaringClass);
}

/**
Expand All @@ -221,7 +221,7 @@ public static void registerAllDeclaredConstructors(Class<?> declaringClass) {
* @since 23.0
*/
public static void registerAllFields(Class<?> declaringClass) {
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerAllFieldsQuery(ConfigurationCondition.alwaysTrue(), declaringClass);
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerAllFields(ConfigurationCondition.alwaysTrue(), declaringClass);
}

/**
Expand All @@ -231,7 +231,7 @@ public static void registerAllFields(Class<?> declaringClass) {
* @since 23.0
*/
public static void registerAllDeclaredFields(Class<?> declaringClass) {
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerAllDeclaredFieldsQuery(ConfigurationCondition.alwaysTrue(), declaringClass);
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerAllDeclaredFields(ConfigurationCondition.alwaysTrue(), declaringClass);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import java.util.Arrays;

public interface ReflectionRegistry {
// TODO thread this true behind MRE flag
default void register(ConfigurationCondition condition, Class<?>... classes) {
Arrays.stream(classes).forEach(clazz -> register(condition, false, clazz));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ public interface RuntimeReflectionSupport extends ReflectionRegistry {

void registerAllDeclaredMethodsQuery(ConfigurationCondition condition, boolean queriedOnly, Class<?> clazz);

void registerAllFieldsQuery(ConfigurationCondition condition, Class<?> clazz);
void registerAllFields(ConfigurationCondition condition, Class<?> clazz);

void registerAllDeclaredFieldsQuery(ConfigurationCondition condition, Class<?> clazz);
void registerAllDeclaredFields(ConfigurationCondition condition, Class<?> clazz);

void registerAllConstructorsQuery(ConfigurationCondition condition, boolean queriedOnly, Class<?> clazz);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

import com.oracle.graal.pointsto.meta.AnalysisMethod;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.util.ReflectionUtil;

import jdk.graal.compiler.api.replacements.Fold;

Expand All @@ -55,7 +56,7 @@ public void setBigBang(BigBang bb) {
}

public static boolean isClassIncludedBase(Class<?> cls) {
Class<?> enclosingClass = cls.getEnclosingClass();
Class<?> enclosingClass = ReflectionUtil.linkageSafeQuery(cls, null, Class::getEnclosingClass);
return !Feature.class.isAssignableFrom(cls) && !AnnotationAccess.isAnnotationPresent(cls, TargetClass.class) && (enclosingClass == null || isClassIncludedBase(enclosingClass));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ public void onTypeInstantiated(AnalysisType type) {
/* Register the type as instantiated with all its super types. */

assert type.isInstantiated() : type;
AnalysisError.guarantee(type.isArray() || (type.isInstanceClass() && !type.isAbstract()));
AnalysisError.guarantee(type.isArray() || (type.isInstanceClass() && !type.isAbstract()), "Type %s must be either an array, or a non abstract instance class", type.getName());

TypeState typeState = TypeState.forExactType(this, type, true);
TypeState typeStateNonNull = TypeState.forExactType(this, type, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public TypeResult<ConfigurationType> resolveType(UnresolvedConfigurationConditio
}

@Override
public void registerType(UnresolvedConfigurationCondition condition, ConfigurationType type) {
public void registerType(UnresolvedConfigurationCondition condition, ConfigurationType type, boolean registerMetadata) {
VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type");
configuration.add(type);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1284,19 +1284,19 @@ public enum ReportingMode {
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllFromModule = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());

@Option(help = "Include all classes, methods, fields, and resources from a given module for dynamic access", type = OptionType.Debug) //
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllMetadataForModule = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> EnableDynamicAccessForModule = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());

@Option(help = "Include all classes, methods, fields, and resources from given paths", type = OptionType.Debug) //
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllFromPath = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());

@Option(help = "Include all classes, methods, fields, and resources from given paths for dynamic access", type = OptionType.Debug) //
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllMetadataForClassPathEntry = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> EnableDynamicAccessForClassPathEntry = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());

@Option(help = "Include all classes, methods, fields, and resources from the class path", type = OptionType.Debug) //
public static final HostedOptionKey<Boolean> IncludeAllFromClassPath = new HostedOptionKey<>(false);

@Option(help = "Include all classes, methods, fields, and resources for dynamic access for the whole classpath", type = OptionType.Debug) //
public static final HostedOptionKey<Boolean> IncludeAllMetadataForClassPath = new HostedOptionKey<>(false);
public static final HostedOptionKey<Boolean> EnableDynamicAccess = new HostedOptionKey<>(false);

public static boolean includeAll() {
return IncludeAllFromModule.hasBeenSet() || IncludeAllFromPath.hasBeenSet() || IncludeAllFromClassPath.hasBeenSet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ protected void parseClass(EconomicMap<String, Object> data) {

C queryCondition = isType ? conditionResolver.alwaysTrue() : condition;
T clazz = result.get();
delegate.registerType(conditionResult.get(), clazz);
delegate.registerType(conditionResult.get(), clazz, false);

registerIfNotDefault(data, false, clazz, "allDeclaredConstructors", () -> delegate.registerDeclaredConstructors(condition, false, clazz));
registerIfNotDefault(data, false, clazz, "allPublicConstructors", () -> delegate.registerPublicConstructors(condition, false, clazz));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public interface ReflectionConfigurationParserDelegate<C, T> {

TypeResult<T> resolveType(C condition, ConfigurationTypeDescriptor typeDescriptor, boolean allowPrimitives);

void registerType(C condition, T type);
void registerType(C condition, T type, boolean registerMetadata);

void registerPublicClasses(C condition, T type);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ protected void parseClass(EconomicMap<String, Object> data) {

C queryCondition = conditionResolver.alwaysTrue();
T clazz = result.get();
delegate.registerType(conditionResult.get(), clazz);
delegate.registerType(conditionResult.get(), clazz, true);

delegate.registerDeclaredClasses(queryCondition, clazz);
delegate.registerRecordComponents(queryCondition, clazz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ public void collectResources(ResourceCollector resourceCollector) {

/* Collect remaining resources from classpath */
classLoaderSupport.classpath().stream().parallel().forEach(classpathFile -> {
boolean includeCurrent = classLoaderSupport.getJavaPathsToInclude().contains(classpathFile) || classLoaderSupport.includeAllFromClassPath() ||
classLoaderSupport.getPathsToIncludeMetadata().contains(classpathFile) || classLoaderSupport.isIncludeAllMetadataFromClassPath();
boolean includeCurrent = classLoaderSupport.getPathsToInclude().contains(classpathFile) || classLoaderSupport.includeAllFromClassPath() ||
classLoaderSupport.getClassPathEntriesToEnableDynamicAccess().contains(classpathFile) || classLoaderSupport.isEnableDynamicAccessForClassPath();
try {
if (Files.isDirectory(classpathFile)) {
scanDirectory(classpathFile, resourceCollector, includeCurrent);
Expand All @@ -134,7 +134,7 @@ private void collectResourceFromModule(ResourceCollector resourceCollector, Reso
ModuleReference moduleReference = info.resolvedModule.reference();
try (ModuleReader moduleReader = moduleReference.open()) {
boolean includeCurrent = classLoaderSupport.getModuleNamesToInclude().contains(info.resolvedModule().name()) ||
classLoaderSupport.getModuleNamesToIncludeMetadata().contains(info.resolvedModule().name());
classLoaderSupport.getModuleNamesToEnableDynamicAccess().contains(info.resolvedModule().name());
List<ConditionalResource> resourcesFound = new ArrayList<>();
moduleReader.list().forEach(resourceName -> {
var conditionsWithOrigins = shouldIncludeEntry(info.module, resourceCollector, resourceName, moduleReference.location().orElse(null), includeCurrent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromClassPath;
import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromModule;
import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromPath;
import static com.oracle.svm.core.SubstrateOptions.IncludeAllMetadataForModule;
import static com.oracle.svm.core.SubstrateOptions.IncludeAllMetadataForClassPath;
import static com.oracle.svm.core.SubstrateOptions.IncludeAllMetadataForClassPathEntry;
import static com.oracle.svm.core.SubstrateOptions.EnableDynamicAccessForModule;
import static com.oracle.svm.core.SubstrateOptions.EnableDynamicAccess;
import static com.oracle.svm.core.SubstrateOptions.EnableDynamicAccessForClassPathEntry;
import static com.oracle.svm.core.util.VMError.guarantee;
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;

Expand Down Expand Up @@ -131,14 +131,14 @@ public final class NativeImageClassLoaderSupport {

public final AnnotationExtractor annotationExtractor;

private Set<String> javaModuleNamesToInclude;
private Set<String> moduleNamesToIncludeMetadata;
private Set<String> moduleNamesToInclude;
private Set<String> moduleNamesToEnableDynamicAccess;

private Set<Path> javaPathsToInclude;
private Set<Path> pathsToIncludeMetadata;
private Set<Path> pathsToInclude;
private Set<Path> classPathEntriesToEnableDynamicAccess;

private boolean includeAllFromClassPath;
private boolean includeAllMetadataFromClassPath;
private boolean enableDynamicAccessForClassPath;

private Optional<LibGraalClassLoaderBase> libGraalLoader;
private List<ClassLoader> classLoaders;
Expand Down Expand Up @@ -254,16 +254,16 @@ private static Path stringToPath(String path) {
}

public void loadAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoader) {
guarantee(javaModuleNamesToInclude == null, "This method should be executed only once.");
guarantee(moduleNamesToInclude == null, "This method should be executed only once.");

javaModuleNamesToInclude = collectAndVerifyModulesFromOption(IncludeAllFromModule);
moduleNamesToIncludeMetadata = collectAndVerifyModulesFromOption(IncludeAllMetadataForModule);
moduleNamesToInclude = collectAndVerifyModulesFromOption(IncludeAllFromModule);
moduleNamesToEnableDynamicAccess = collectAndVerifyModulesFromOption(EnableDynamicAccessForModule);

javaPathsToInclude = collectAndVerifyPathsFromOption(IncludeAllFromPath);
pathsToIncludeMetadata = collectAndVerifyPathsFromOption(IncludeAllMetadataForClassPathEntry);
pathsToInclude = collectAndVerifyPathsFromOption(IncludeAllFromPath);
classPathEntriesToEnableDynamicAccess = collectAndVerifyPathsFromOption(EnableDynamicAccessForClassPathEntry);

includeAllFromClassPath = IncludeAllFromClassPath.getValue(parsedHostedOptions);
includeAllMetadataFromClassPath = IncludeAllMetadataForClassPath.getValue(parsedHostedOptions);
enableDynamicAccessForClassPath = EnableDynamicAccess.getValue(parsedHostedOptions);

new LoadClassHandler(executor, imageClassLoader).run();

Expand Down Expand Up @@ -763,7 +763,7 @@ private void run() {
"org.graalvm.nativebridge"));

Set<String> additionalSystemModules = upgradeAndSystemModuleFinder.findAll().stream().map(v -> v.descriptor().name()).collect(Collectors.toSet());
additionalSystemModules.retainAll(getModuleNamesToIncludeMetadata());
additionalSystemModules.retainAll(getModuleNamesToEnableDynamicAccess());
requiresInit.addAll(additionalSystemModules);

for (ModuleReference moduleReference : upgradeAndSystemModuleFinder.findAll()) {
Expand All @@ -790,8 +790,8 @@ private void initModule(ModuleReference moduleReference) {
}
try (ModuleReader moduleReader = moduleReference.open()) {
Module module = optionalModule.get();
final boolean includeUnconditionally = javaModuleNamesToInclude.contains(module.getName());
final boolean includeForReflection = moduleNamesToIncludeMetadata.contains(module.getName());
final boolean includeUnconditionally = moduleNamesToInclude.contains(module.getName());
final boolean includeForReflection = moduleNamesToEnableDynamicAccess.contains(module.getName());
var container = moduleReference.location().orElseThrow();
if (ModuleLayer.boot().equals(module.getLayer())) {
builderURILocations.add(container);
Expand All @@ -811,8 +811,8 @@ private void initModule(ModuleReference moduleReference) {
}

private void loadClassesFromPath(Path path) {
final boolean includeUnconditionally = javaPathsToInclude.contains(path) || includeAllFromClassPath;
final boolean includeAllMetadata = pathsToIncludeMetadata.contains(path) || includeAllMetadataFromClassPath;
final boolean includeUnconditionally = pathsToInclude.contains(path) || includeAllFromClassPath;
final boolean includeAllMetadata = classPathEntriesToEnableDynamicAccess.contains(path) || enableDynamicAccessForClassPath;
if (ClasspathUtils.isJar(path)) {
try {
URI container = path.toAbsolutePath().toUri();
Expand Down Expand Up @@ -1031,27 +1031,27 @@ public void reportBuilderClassesInApplication() {
}

public Set<String> getModuleNamesToInclude() {
return javaModuleNamesToInclude;
return moduleNamesToInclude;
}

public Set<String> getModuleNamesToIncludeMetadata() {
return moduleNamesToIncludeMetadata;
public Set<String> getModuleNamesToEnableDynamicAccess() {
return moduleNamesToEnableDynamicAccess;
}

public Set<Path> getJavaPathsToInclude() {
return javaPathsToInclude;
public Set<Path> getPathsToInclude() {
return pathsToInclude;
}

public Set<Path> getPathsToIncludeMetadata() {
return pathsToIncludeMetadata;
public Set<Path> getClassPathEntriesToEnableDynamicAccess() {
return classPathEntriesToEnableDynamicAccess;
}

public boolean includeAllFromClassPath() {
return includeAllFromClassPath;
}

public boolean isIncludeAllMetadataFromClassPath() {
return includeAllMetadataFromClassPath;
public boolean isEnableDynamicAccessForClassPath() {
return enableDynamicAccessForClassPath;
}

public List<Class<?>> getClassesToIncludeUnconditionally() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.file.FileSystems;
Expand Down Expand Up @@ -75,7 +77,9 @@
import org.graalvm.nativeimage.hosted.RuntimeSerialization;
import org.graalvm.nativeimage.impl.AnnotationExtractor;
import org.graalvm.nativeimage.impl.CConstantValueSupport;
import org.graalvm.nativeimage.impl.ConfigurationCondition;
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;
import org.graalvm.nativeimage.impl.RuntimeReflectionSupport;
import org.graalvm.nativeimage.impl.SizeOfSupport;
import org.graalvm.word.PointerBase;

Expand Down Expand Up @@ -1085,23 +1089,28 @@ protected void setupNativeImage(String imageName, OptionValues options, Map<Meth
}
}

private static void registerClassFullyForReflection(Class<?> cls) {
RuntimeReflection.register(cls);
RuntimeJNIAccess.register(cls);
for (Method declaredMethod : cls.getDeclaredMethods()) {
RuntimeReflection.register(declaredMethod);
private static void registerClassFullyForReflection(Class<?> clazz) {
RuntimeReflection.register(clazz);

RuntimeReflection.registerAllDeclaredFields(clazz);
RuntimeReflection.registerAllDeclaredMethods(clazz);
RuntimeReflection.registerAllDeclaredConstructors(clazz);

RuntimeJNIAccess.register(clazz);
for (Method declaredMethod : ReflectionUtil.linkageSafeQuery(clazz, new Method[0], Class::getDeclaredMethods)) {
RuntimeJNIAccess.register(declaredMethod);
}
RuntimeReflection.registerAllDeclaredFields(cls);
RuntimeReflection.registerAllFields(cls);
RuntimeReflection.registerAllMethods(cls);
RuntimeReflection.registerAllDeclaredMethods(cls);

for (var declaredField : cls.getDeclaredFields()) {
RuntimeReflection.register(declaredField);
for (Constructor<?> declaredConstructor : ReflectionUtil.linkageSafeQuery(clazz, new Constructor[0], Class::getDeclaredConstructors)) {
RuntimeJNIAccess.register(declaredConstructor);
}
for (var declaredField : ReflectionUtil.linkageSafeQuery(clazz, new Field[0], Class::getDeclaredFields)) {
RuntimeJNIAccess.register(declaredField);
}
RuntimeSerialization.register(cls);

RuntimeSerialization.register(clazz);
if (!(clazz.isArray() || clazz.isInterface() || clazz.isPrimitive() || Modifier.isAbstract(clazz.getModifiers()))) {
ImageSingletons.lookup(RuntimeReflectionSupport.class).register(ConfigurationCondition.alwaysTrue(), true, clazz);
}
}

protected void registerEntryPointStubs(Map<Method, CEntryPointData> entryPoints) {
Expand Down
Loading

0 comments on commit 1fcdae6

Please sign in to comment.