Skip to content

Commit

Permalink
[GR-48338] Add options to include all classes from the class path
Browse files Browse the repository at this point in the history
PullRequest: graal/16006
  • Loading branch information
Zeavee committed Jun 20, 2024
2 parents 5fc14c4 + ccd5aa3 commit 31132c5
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
package com.oracle.graal.pointsto;

import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -350,17 +353,25 @@ public final boolean executorIsStarted() {

@Override
public void registerTypeForBaseImage(Class<?> cls) {
if (classInclusionPolicy.isClassIncluded(cls)) {
if (getOrDefault(cls, classInclusionPolicy::isClassIncluded, false)) {
classInclusionPolicy.includeClass(cls);
Stream.concat(Arrays.stream(cls.getDeclaredConstructors()), Arrays.stream(cls.getDeclaredMethods()))
Stream.concat(Arrays.stream(getOrDefault(cls, Class::getDeclaredConstructors, new Constructor<?>[0])), Arrays.stream(getOrDefault(cls, Class::getDeclaredMethods, new Method[0])))
.filter(classInclusionPolicy::isMethodIncluded)
.forEach(classInclusionPolicy::includeMethod);
Arrays.stream(cls.getDeclaredFields())
Arrays.stream(getOrDefault(cls, Class::getDeclaredFields, new Field[0]))
.filter(classInclusionPolicy::isFieldIncluded)
.forEach(classInclusionPolicy::includeField);
}
}

public static <T, U> U getOrDefault(T cls, Function<T, U> getMembers, U backup) {
try {
return getMembers.apply(cls);
} catch (NoClassDefFoundError | IncompatibleClassChangeError e) {
return backup;
}
}

/**
* Provide a non-null position. Some flows like newInstance and invoke require a non-null
* position, for others is just better. The constructed position is best-effort, i.e., it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
import java.lang.reflect.Modifier;

import org.graalvm.nativeimage.AnnotationAccess;
import org.graalvm.nativeimage.hosted.Feature;

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

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

Expand All @@ -55,7 +57,10 @@ public void setBigBang(BigBang bb) {
/**
* Determine if the given class needs to be included in the image according to the policy.
*/
public abstract boolean isClassIncluded(Class<?> cls);
public boolean isClassIncluded(Class<?> cls) {
Class<?> enclosingClass = cls.getEnclosingClass();
return !Feature.class.isAssignableFrom(cls) && !AnnotationAccess.isAnnotationPresent(cls, TargetClass.class) && (enclosingClass == null || isClassIncluded(enclosingClass));
}

/**
* Determine if the given method needs to be included in the image according to the policy.
Expand Down Expand Up @@ -126,6 +131,9 @@ public LayeredBaseImageInclusionPolicy(Object reason) {

@Override
public boolean isClassIncluded(Class<?> cls) {
if (!super.isClassIncluded(cls)) {
return false;
}
Class<?> enclosingClass = cls.getEnclosingClass();
int classModifiers = cls.getModifiers();
if (enclosingClass != null) {
Expand Down Expand Up @@ -172,11 +180,6 @@ public DefaultAllInclusionPolicy(Object reason) {
super(reason);
}

@Override
public boolean isClassIncluded(Class<?> cls) {
return true;
}

@Override
public void includeMethod(Executable method) {
bb.postTask(debug -> bb.addRootMethod(method, false, reason));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1231,8 +1231,11 @@ public enum ReportingMode {
@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 the class path", type = OptionType.Debug) //
public static final HostedOptionKey<Boolean> IncludeAllFromClassPath = new HostedOptionKey<>(false);

public static boolean includeAll() {
return IncludeAllFromModule.hasBeenSet() || IncludeAllFromPath.hasBeenSet();
return IncludeAllFromModule.hasBeenSet() || IncludeAllFromPath.hasBeenSet() || IncludeAllFromClassPath.hasBeenSet();
}

@Option(help = "Run layered image base layer open-world analysis. Includes all public types and methods that can be reached using normal Java access rules.")//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public void collectResources(ResourceCollector resourceCollector) {

/* Collect remaining resources from classpath */
classLoaderSupport.classpath().stream().parallel().forEach(classpathFile -> {
boolean includeCurrent = classLoaderSupport.getJavaPathsToInclude().contains(classpathFile);
boolean includeCurrent = classLoaderSupport.getJavaPathsToInclude().contains(classpathFile) || classLoaderSupport.includeAllFromClassPath();
try {
if (Files.isDirectory(classpathFile)) {
scanDirectory(classpathFile, resourceCollector, includeCurrent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package com.oracle.svm.hosted;

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.util.VMError.guarantee;
Expand Down Expand Up @@ -77,8 +78,6 @@
import org.graalvm.collections.EconomicSet;
import org.graalvm.collections.MapCursor;
import org.graalvm.collections.Pair;
import jdk.graal.compiler.options.OptionKey;
import jdk.graal.compiler.options.OptionValues;
import org.graalvm.nativeimage.impl.AnnotationExtractor;

import com.oracle.svm.core.NativeImageClassLoaderOptions;
Expand All @@ -98,6 +97,8 @@
import com.oracle.svm.util.ModuleSupport;
import com.oracle.svm.util.ReflectionUtil;

import jdk.graal.compiler.options.OptionKey;
import jdk.graal.compiler.options.OptionValues;
import jdk.internal.module.Modules;

public class NativeImageClassLoaderSupport {
Expand All @@ -124,6 +125,7 @@ public class NativeImageClassLoaderSupport {

private Set<String> javaModuleNamesToInclude;
private Set<Path> javaPathsToInclude;
private boolean includeAllFromClassPath;

private final Set<Class<?>> classesToIncludeUnconditionally = Collections.newSetFromMap(new ConcurrentHashMap<>());

Expand Down Expand Up @@ -239,6 +241,8 @@ public void loadAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoa
.filter(p -> !classpath().contains(p))
.findAny().ifPresent(p -> missingFromSetOfEntriesError(p, classpath(), "classpath", IncludeAllFromPath));

includeAllFromClassPath = IncludeAllFromClassPath.getValue(parsedHostedOptions);

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

Expand Down Expand Up @@ -705,7 +709,7 @@ private void initModule(ModuleReference moduleReference) {
}

private void loadClassesFromPath(Path path) {
final boolean includeUnconditionally = javaPathsToInclude.contains(path);
final boolean includeUnconditionally = javaPathsToInclude.contains(path) || includeAllFromClassPath;
if (ClasspathUtils.isJar(path)) {
try {
URI container = path.toAbsolutePath().toUri();
Expand Down Expand Up @@ -924,6 +928,10 @@ public Set<Path> getJavaPathsToInclude() {
return javaPathsToInclude;
}

public boolean includeAllFromClassPath() {
return includeAllFromClassPath;
}

public List<Class<?>> getClassesToIncludeUnconditionally() {
return classesToIncludeUnconditionally.stream()
.sorted(Comparator.comparing(Class::getTypeName))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,10 @@ public void onTypeReachable(AnalysisType type) {
* Using getInstanceFields and getStaticFields allows to include the fields from the
* substitution class.
*/
Stream.concat(Arrays.stream(type.getInstanceFields(true)), Arrays.stream(type.getStaticFields()))
Stream.concat(Arrays.stream(getOrDefault(type, t -> t.getInstanceFields(true), new AnalysisField[0])),
Arrays.stream(getOrDefault(type, AnalysisType::getStaticFields, new AnalysisField[0])))
.map(OriginalFieldProvider::getJavaField)
.filter(classInclusionPolicy::isFieldIncluded)
.filter(field -> field != null && classInclusionPolicy.isFieldIncluded(field))
.forEach(classInclusionPolicy::includeField);
}
});
Expand Down

0 comments on commit 31132c5

Please sign in to comment.