Skip to content

Commit

Permalink
Options to include metadata for module, package or classpath
Browse files Browse the repository at this point in the history
  • Loading branch information
vjovanov committed Jan 14, 2025
1 parent 2d50264 commit bb5696b
Show file tree
Hide file tree
Showing 17 changed files with 199 additions and 74 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
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ At runtime, premain runtime options are set along with main class' arguments in
* (GR-60081) Native Image now targets `armv8.1-a` by default on AArch64. Use `-march=compatibility` for best compatibility or `-march=native` for best performance if the native executable is deployed on the same machine or on a machine with the same CPU features. To list all available machine types, use `-march=list`.
* (GR-60234) Remove `"customTargetConstructorClass"` field from the serialization JSON metadata. All possible constructors are now registered by default when registering a type for serialization. `RuntimeSerialization.registerWithTargetConstructorClass` is now deprecated.
* (GR-60237) Include serialization JSON reachability metadata as part of reflection metadata by introducing the `"serializable"` flag for reflection entries.
* (GR-54953) Add options `-H:IncludeAllMetadataForClassPathEntry`, `-H:+IncludeAllForClassPath`, and `-H:IncludeAllMetadataForModule` for bulk inclusion of reachability metadata.

## GraalVM for JDK 23 (Internal Version 24.1.0)
* (GR-51520) The old class initialization strategy, which was deprecated in GraalVM for JDK 22, is removed. The option `StrictImageHeap` no longer has any effect.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.oracle.graal.pointsto.meta.AnalysisField;
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 @@ -56,12 +57,17 @@ public void setBigBang(BigBang bb) {
this.bb = bb;
}

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

/**
* Determine if the given class needs to be included in the image according to the policy.
*/
public boolean isClassIncluded(Class<?> cls) {
Class<?> enclosingClass = cls.getEnclosingClass();
return !Feature.class.isAssignableFrom(cls) && !AnnotationAccess.isAnnotationPresent(cls, TargetClass.class) && (enclosingClass == null || isClassIncluded(enclosingClass));
return isClassIncludedBase(cls) && (enclosingClass == null || isClassIncluded(enclosingClass));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,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 @@ -1301,16 +1301,29 @@ public enum ReportingMode {
@Option(help = "Include all classes, methods, and fields from given modules", type = OptionType.Debug) //
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> 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 and fields from the given packages", type = OptionType.Debug) //
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllFromPackage = new HostedOptionKey<>(
AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());

@Option(help = "Include all classes, methods and fields from the given packages for dynamic access", type = OptionType.Debug) //
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> EnableDynamicAccessForPackage = new HostedOptionKey<>(
AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());

@Option(help = "Include all classes, methods, fields, and resources from given paths for dynamic access", type = OptionType.Debug) //
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> EnableDynamicAccess = new HostedOptionKey<>(false);

public static boolean includeAll() {
return IncludeAllFromModule.hasBeenSet() || IncludeAllFromPath.hasBeenSet() || IncludeAllFromPackage.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,7 +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();
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 @@ -132,7 +133,8 @@ public void collectResources(ResourceCollector resourceCollector) {
private void collectResourceFromModule(ResourceCollector resourceCollector, ResourceLookupInfo info) {
ModuleReference moduleReference = info.resolvedModule.reference();
try (ModuleReader moduleReader = moduleReference.open()) {
boolean includeCurrent = classLoaderSupport.getJavaModuleNamesToInclude().contains(info.resolvedModule().name());
boolean includeCurrent = classLoaderSupport.getModuleNamesToInclude().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
Loading

0 comments on commit bb5696b

Please sign in to comment.