diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index 8cc794f41f24..194420b7268c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -90,9 +90,11 @@ public class NativeImageGeneratorRunner { - private volatile NativeImageGenerator generator; + public static final String NATIVE_IMAGE_MODULE_PREFIX = "org.graalvm.nativeimage."; public static final String IMAGE_BUILDER_ARG_FILE_OPTION = "--image-args-file="; + private volatile NativeImageGenerator generator; + public enum BuildOutcome { SUCCESSFUL, FAILED, @@ -189,11 +191,7 @@ public void run() { private static void checkBootModuleDependencies(boolean verbose) { Set allModules = ModuleLayer.boot().modules(); - List builderModules = allModules.stream().filter(m -> m.isNamed() && m.getName().startsWith("org.graalvm.nativeimage.")).toList(); - Set transitiveBuilderModules = new LinkedHashSet<>(); - for (Module svmModule : builderModules) { - transitiveReaders(svmModule, allModules, transitiveBuilderModules); - } + Set transitiveBuilderModules = getNativeImageBuilderModules(); if (verbose) { System.out.println(transitiveBuilderModules.stream() .map(Module::getName) @@ -234,6 +232,28 @@ private static void checkBootModuleDependencies(boolean verbose) { } } + /** + * Returns what are considered native-image builder modules: those are the modules with prefix + * {@value NativeImageGeneratorRunner#NATIVE_IMAGE_MODULE_PREFIX} and their reader modules. + */ + public static Set getNativeImageBuilderModules() { + final var allModules = ModuleLayer.boot().modules(); + List builderModules = new ArrayList<>(allModules.size()); + for (Module m : allModules) { + if (m.isNamed()) { + if (m.getName().startsWith(NATIVE_IMAGE_MODULE_PREFIX)) { + builderModules.add(m); + } + } + } + + Set transitiveBuilderModules = new LinkedHashSet<>(); + for (Module svmModule : builderModules) { + transitiveReaders(svmModule, allModules, transitiveBuilderModules); + } + return transitiveBuilderModules; + } + public static void transitiveReaders(Module readModule, Set potentialReaders, Set actualReaders) { for (Module potentialReader : potentialReaders) { if (potentialReader.canRead(readModule)) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstitutionReportFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstitutionReportFeature.java index 41ec30b59876..2757831c8017 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstitutionReportFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstitutionReportFeature.java @@ -30,9 +30,6 @@ import java.util.TreeMap; import java.util.function.Function; -import jdk.graal.compiler.options.Option; - -import com.oracle.svm.util.OriginalClassProvider; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -44,27 +41,56 @@ import com.oracle.svm.hosted.substitute.SubstitutionField; import com.oracle.svm.hosted.substitute.SubstitutionMethod; import com.oracle.svm.hosted.substitute.SubstitutionType; +import com.oracle.svm.util.OriginalClassProvider; +import jdk.graal.compiler.options.Option; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +/// Feature that reports substitutions discovered during analysis: all with [Options#ReportPerformedSubstitutions], +/// or only user-authored with [Options#ReportPerformedUserSubstitutions]. +/// > Note: The feature does not report `@Delete`, `@RecomputeFieldValue`, and `@InjectAccessors` annotations. +/// +/// When enabled via [Options#ReportPerformedSubstitutions] or [Options#ReportPerformedUserSubstitutions], +/// this feature scans the analysis universe after the analysis phase completes and collects substitutions: +/// - type substitutions ([SubstitutionType]) +/// - method substitutions ([SubstitutionMethod]) +/// - field substitutions ([SubstitutionField]) +/// +/// The results are emitted as a CSV report using [ReportUtils] under the [SubstrateOptions#reportsPath()] directory. +/// The report is named: +/// `substitutions__