Skip to content

Commit c8be4d3

Browse files
committed
[GR-57117] Make --layer-create=package=... take package name instead of cp entry.
PullRequest: graal/19259
2 parents d729cb9 + 600350a commit c8be4d3

File tree

9 files changed

+153
-79
lines changed

9 files changed

+153
-79
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,14 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean o
130130
}
131131
});
132132

133-
// @APIOption(name = "layer-create")//
133+
public static final String LAYER_OPTION_PREFIX = "-H:Layer"; // "--layer"
134+
public static final String LAYER_CREATE_OPTION = LAYER_OPTION_PREFIX + "Create"; // "-create"
135+
// @APIOption(name = LAYER_CREATE_OPTION) // use when non-experimental
134136
@Option(help = "Experimental: Build a Native Image layer.")//
135137
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> LayerCreate = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
136138

137-
// @APIOption(name = "layer-use")//
139+
// public static final String LAYER_USE_OPTION = LAYER_OPTION_PREFIX + "-use";
140+
// @APIOption(name = LAYER_USE_OPTION) // use when non-experimental
138141
@Option(help = "Experimental: Build an image based on a Native Image layer.")//
139142
@BundleMember(role = Role.Input) //
140143
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Paths> LayerUse = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Paths.build());
@@ -1286,11 +1289,15 @@ public enum ReportingMode {
12861289
@Option(help = "Include all classes, methods, fields, and resources from given paths", type = OptionType.Debug) //
12871290
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllFromPath = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
12881291

1292+
@Option(help = "Include all classes, methods and fields from the given packages", type = OptionType.Debug) //
1293+
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllFromPackage = new HostedOptionKey<>(
1294+
AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
1295+
12891296
@Option(help = "Include all classes, methods, fields, and resources from the class path", type = OptionType.Debug) //
12901297
public static final HostedOptionKey<Boolean> IncludeAllFromClassPath = new HostedOptionKey<>(false);
12911298

12921299
public static boolean includeAll() {
1293-
return IncludeAllFromModule.hasBeenSet() || IncludeAllFromPath.hasBeenSet() || IncludeAllFromClassPath.hasBeenSet();
1300+
return IncludeAllFromModule.hasBeenSet() || IncludeAllFromPath.hasBeenSet() || IncludeAllFromPackage.hasBeenSet() || IncludeAllFromClassPath.hasBeenSet();
12941301
}
12951302

12961303
@Option(help = "Force include include all public types and methods that can be reached using normal Java access rules.")//

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@
3131
import java.util.regex.Pattern;
3232
import java.util.regex.PatternSyntaxException;
3333

34+
import com.oracle.svm.core.SubstrateOptions;
3435
import com.oracle.svm.core.VM;
3536
import com.oracle.svm.core.option.OptionOrigin;
3637
import com.oracle.svm.core.util.ExitStatus;
3738
import com.oracle.svm.driver.NativeImage.ArgumentQueue;
39+
import com.oracle.svm.hosted.imagelayer.LayerArchiveSupport;
40+
import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.ExtendedOption;
41+
import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.LayerOption;
3842
import com.oracle.svm.util.LogUtils;
3943

4044
import jdk.graal.compiler.options.OptionType;
@@ -138,6 +142,25 @@ private boolean consume(ArgumentQueue args, String headArg) {
138142
return true;
139143
}
140144

145+
if (headArg.startsWith(SubstrateOptions.LAYER_CREATE_OPTION)) {
146+
String layerCreateValue = headArg.substring(SubstrateOptions.LAYER_CREATE_OPTION.length());
147+
if (!layerCreateValue.isEmpty()) {
148+
LayerOption layerOption = LayerOption.parse(layerCreateValue);
149+
for (ExtendedOption option : layerOption.extendedOptions()) {
150+
switch (option.key()) {
151+
case LayerArchiveSupport.PACKAGE_OPTION -> {
152+
String packageName = option.value();
153+
String moduleName = nativeImage.systemPackagesToModules.get(packageName);
154+
if (moduleName != null) {
155+
nativeImage.addAddedModules(moduleName);
156+
}
157+
}
158+
}
159+
}
160+
}
161+
return false;
162+
}
163+
141164
if (headArg.startsWith(DEBUG_ATTACH_OPTION)) {
142165
if (useDebugAttach) {
143166
throw NativeImage.showError("The " + DEBUG_ATTACH_OPTION + " option can only be used once.");

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,19 @@ private static String flagsFileName(String versionTag) {
145145

146146
static final Map<String, String[]> graalCompilerFlags = getCompilerFlags();
147147

148+
private static Map<String, String> getSystemPackages() {
149+
Map<String, String> res = new HashMap<>();
150+
for (ModuleReference moduleRef : ModuleFinder.ofSystem().findAll()) {
151+
ModuleDescriptor moduleDescriptor = moduleRef.descriptor();
152+
for (String packageName : moduleDescriptor.packages()) {
153+
res.put(packageName, moduleDescriptor.name());
154+
}
155+
}
156+
return Map.copyOf(res);
157+
}
158+
159+
final Map<String, String> systemPackagesToModules = getSystemPackages();
160+
148161
static String getResource(String resourceName) {
149162
try (InputStream input = NativeImage.class.getResourceAsStream(resourceName)) {
150163
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
@@ -963,7 +976,7 @@ private void prepareImageBuildArgs() {
963976

964977
/*
965978
* The presence of CDS and custom system class loaders disables the use of archived
966-
* non-system class and and triggers a warning.
979+
* non-system class and triggers a warning.
967980
*/
968981
addImageBuilderJavaArgs("-Xshare:off");
969982

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public void afterAnalysis(AfterAnalysisAccess access) {
217217
* Parse explicitly added modules via --add-modules. This is done early as this information
218218
* is required when filtering the analysis reachable module set.
219219
*/
220-
Set<String> extraModules = ModuleLayerFeatureUtils.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_ADDED_MODULES);
220+
Set<String> extraModules = ModuleSupport.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_ADDED_MODULES);
221221
extraModules.addAll(Resources.getIncludedResourcesModules());
222222
extraModules.stream().filter(Predicate.not(ModuleSupport.nonExplicitModules::contains)).forEach(moduleName -> {
223223
Optional<?> module = accessImpl.imageClassLoader.findModule(moduleName);
@@ -282,7 +282,7 @@ private Set<String> calculateRootModules(Collection<String> addModules) {
282282
ModuleFinder upgradeModulePath = NativeImageClassLoaderSupport.finderFor("jdk.module.upgrade.path");
283283
ModuleFinder appModulePath = moduleLayerFeatureUtils.getAppModuleFinder();
284284
String mainModule = ModuleLayerFeatureUtils.getMainModuleName();
285-
Set<String> limitModules = ModuleLayerFeatureUtils.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_LIMITED_MODULES);
285+
Set<String> limitModules = ModuleSupport.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_LIMITED_MODULES);
286286

287287
Object systemModules = null;
288288
ModuleFinder systemModuleFinder;
@@ -658,7 +658,8 @@ private static final class ModuleLayerFeatureUtils {
658658
ModuleLayerFeatureUtils(ImageClassLoader cl) {
659659
runtimeModules = new HashMap<>();
660660
imageClassLoader = cl;
661-
nativeAccessEnabled = NativeImageClassLoaderOptions.EnableNativeAccess.getValue().values().stream().flatMap(m -> Arrays.stream(SubstrateUtil.split(m, ",")))
661+
nativeAccessEnabled = NativeImageClassLoaderOptions.EnableNativeAccess.getValue().values().stream()
662+
.flatMap(m -> Arrays.stream(SubstrateUtil.split(m, ",")))
662663
.collect(Collectors.toSet());
663664

664665
Method classGetDeclaredMethods0Method = ReflectionUtil.lookupMethod(Class.class, "getDeclaredFields0", boolean.class);
@@ -770,15 +771,6 @@ static String formatModule(Module module) {
770771
}
771772
}
772773

773-
static Set<String> parseModuleSetModifierProperty(String prop) {
774-
Set<String> specifiedModules = new HashSet<>();
775-
String args = System.getProperty(prop, "");
776-
if (!args.isEmpty()) {
777-
specifiedModules.addAll(Arrays.asList(SubstrateUtil.split(args, ",")));
778-
}
779-
return specifiedModules;
780-
}
781-
782774
static int distanceFromBootModuleLayer(ModuleLayer layer) {
783775
if (layer == ModuleLayer.boot()) {
784776
return 0;

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromClassPath;
2828
import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromModule;
29+
import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromPackage;
2930
import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromPath;
3031
import static com.oracle.svm.core.util.VMError.guarantee;
3132
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
@@ -74,14 +75,14 @@
7475
import java.util.stream.Collectors;
7576
import java.util.stream.Stream;
7677

77-
import com.oracle.svm.core.SubstrateUtil;
7878
import org.graalvm.collections.EconomicMap;
7979
import org.graalvm.collections.EconomicSet;
8080
import org.graalvm.collections.MapCursor;
8181
import org.graalvm.nativeimage.impl.AnnotationExtractor;
8282

8383
import com.oracle.svm.core.NativeImageClassLoaderOptions;
8484
import com.oracle.svm.core.SubstrateOptions;
85+
import com.oracle.svm.core.SubstrateUtil;
8586
import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue;
8687
import com.oracle.svm.core.option.HostedOptionKey;
8788
import com.oracle.svm.core.option.LocatableMultiOptionValue.ValueWithOrigin;
@@ -129,13 +130,15 @@ public final class NativeImageClassLoaderSupport {
129130
public final AnnotationExtractor annotationExtractor;
130131

131132
private Set<String> javaModuleNamesToInclude;
133+
private Set<String> javaPackagesToInclude;
132134
private Set<Path> javaPathsToInclude;
133135
private boolean includeAllFromClassPath;
134136

135137
private Optional<LibGraalClassLoaderBase> libGraalLoader;
136138
private List<ClassLoader> classLoaders;
137139

138-
private final Set<Class<?>> classesToIncludeUnconditionally = Collections.newSetFromMap(new ConcurrentHashMap<>());
140+
private final Set<Class<?>> classesToIncludeUnconditionally = ConcurrentHashMap.newKeySet();
141+
private final Set<String> includedJavaPackages = ConcurrentHashMap.newKeySet();
139142

140143
private final Method implAddReadsAllUnnamed = ReflectionUtil.lookupMethod(Module.class, "implAddReadsAllUnnamed");
141144
private final Method implAddEnableNativeAccess = ReflectionUtil.lookupMethod(Module.class, "implAddEnableNativeAccess");
@@ -244,7 +247,7 @@ private static Path stringToPath(String path) {
244247
}
245248

246249
public void loadAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoader) {
247-
guarantee(javaModuleNamesToInclude == null, "This method should be executed only once.");
250+
guarantee(javaModuleNamesToInclude == null && javaPackagesToInclude == null, "This method should be executed only once.");
248251
javaModuleNamesToInclude = Collections.unmodifiableSet(new HashSet<>(IncludeAllFromModule.getValue(parsedHostedOptions).values()));
249252
/* Verify all modules are present */
250253
final Set<String> allModules = Stream.concat(modulepathModuleFinder.findAll().stream(), upgradeAndSystemModuleFinder.findAll().stream())
@@ -254,6 +257,8 @@ public void loadAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoa
254257
.filter(m -> !allModules.contains(m))
255258
.findAny().ifPresent(m -> missingFromSetOfEntriesError(m, allModules, "module-path", IncludeAllFromModule));
256259

260+
javaPackagesToInclude = Set.copyOf(IncludeAllFromPackage.getValue(parsedHostedOptions).values());
261+
257262
javaPathsToInclude = IncludeAllFromPath.getValue(parsedHostedOptions).values().stream()
258263
.map(NativeImageClassLoaderSupport::stringToPath)
259264
.map(Path::toAbsolutePath)
@@ -722,32 +727,44 @@ private void run() {
722727
System.out.println("Total processed entries: " + entriesProcessed.longValue() + ", current entry: " + currentlyProcessedEntry);
723728
}, 5, 1, TimeUnit.MINUTES);
724729

725-
List<String> requiresInit = new ArrayList<>(Arrays.asList(
726-
"jdk.internal.vm.ci", "jdk.graal.compiler", "com.oracle.graal.graal_enterprise",
730+
var requiresInit = new HashSet<>(List.of("jdk.internal.vm.ci", "jdk.graal.compiler", "com.oracle.graal.graal_enterprise",
727731
"org.graalvm.nativeimage", "org.graalvm.truffle", "org.graalvm.truffle.runtime",
728732
"org.graalvm.truffle.compiler", "com.oracle.truffle.enterprise", "org.graalvm.jniutils",
729733
"org.graalvm.nativebridge"));
730734

731-
Set<String> additionalSystemModules = upgradeAndSystemModuleFinder.findAll().stream().map(v -> v.descriptor().name()).collect(Collectors.toSet());
735+
Set<String> additionalSystemModules = upgradeAndSystemModuleFinder.findAll().stream()
736+
.map(v -> v.descriptor().name())
737+
.collect(Collectors.toSet());
732738
additionalSystemModules.retainAll(getJavaModuleNamesToInclude());
733739
requiresInit.addAll(additionalSystemModules);
734740

741+
Set<String> explicitlyAddedModules = ModuleSupport.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_ADDED_MODULES);
742+
735743
for (ModuleReference moduleReference : upgradeAndSystemModuleFinder.findAll()) {
736-
if (requiresInit.contains(moduleReference.descriptor().name())) {
737-
initModule(moduleReference);
744+
String moduleName = moduleReference.descriptor().name();
745+
boolean moduleRequiresInit = requiresInit.contains(moduleName);
746+
if (moduleRequiresInit || explicitlyAddedModules.contains(moduleName)) {
747+
initModule(moduleReference, moduleRequiresInit);
738748
}
739749
}
740750
for (ModuleReference moduleReference : modulepathModuleFinder.findAll()) {
741-
initModule(moduleReference);
751+
initModule(moduleReference, true);
742752
}
743753

744754
classpath().parallelStream().forEach(this::loadClassesFromPath);
745755
} finally {
746756
scheduledExecutor.shutdown();
747757
}
758+
759+
/* Verify all package inclusion requests were successful */
760+
for (String packageName : javaPackagesToInclude) {
761+
if (!includedJavaPackages.contains(packageName)) {
762+
missingFromSetOfEntriesError(packageName, includedJavaPackages, "package", IncludeAllFromPackage);
763+
}
764+
}
748765
}
749766

750-
private void initModule(ModuleReference moduleReference) {
767+
private void initModule(ModuleReference moduleReference, boolean moduleRequiresInit) {
751768
String moduleReferenceLocation = moduleReference.location().map(URI::toString).orElse("UnknownModuleReferenceLocation");
752769
currentlyProcessedEntry = moduleReferenceLocation;
753770
Optional<Module> optionalModule = findModule(moduleReference.descriptor().name());
@@ -766,7 +783,7 @@ private void initModule(ModuleReference moduleReference) {
766783
String className = extractClassName(moduleResource, fileSystemSeparatorChar);
767784
if (className != null) {
768785
currentlyProcessedEntry = moduleReferenceLocation + fileSystemSeparatorChar + moduleResource;
769-
executor.execute(() -> handleClassFileName(container, module, className, includeUnconditionally));
786+
executor.execute(() -> handleClassFileName(container, module, className, includeUnconditionally, moduleRequiresInit));
770787
}
771788
entriesProcessed.increment();
772789
});
@@ -832,7 +849,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
832849
String className = extractClassName(fileName, fileSystemSeparatorChar);
833850
if (className != null) {
834851
currentlyProcessedEntry = file.toUri().toString();
835-
executor.execute(() -> handleClassFileName(container, null, className, includeUnconditionally));
852+
executor.execute(() -> handleClassFileName(container, null, className, includeUnconditionally, true));
836853
}
837854
entriesProcessed.increment();
838855
return FileVisitResult.CONTINUE;
@@ -916,24 +933,26 @@ private String extractClassName(String fileName, char fileSystemSeparatorChar) {
916933
return strippedClassFileName.equals("module-info") ? null : strippedClassFileName.replace(fileSystemSeparatorChar, '.');
917934
}
918935

919-
private void handleClassFileName(URI container, Module module, String className, boolean includeUnconditionally) {
920-
synchronized (classes) {
921-
EconomicSet<String> classNames = classes.get(container);
922-
if (classNames == null) {
923-
classNames = EconomicSet.create();
924-
classes.put(container, classNames);
936+
private void handleClassFileName(URI container, Module module, String className, boolean includeUnconditionally, boolean classRequiresInit) {
937+
if (classRequiresInit) {
938+
synchronized (classes) {
939+
EconomicSet<String> classNames = classes.get(container);
940+
if (classNames == null) {
941+
classNames = EconomicSet.create();
942+
classes.put(container, classNames);
943+
}
944+
classNames.add(className);
925945
}
926-
classNames.add(className);
927-
}
928-
int packageSep = className.lastIndexOf('.');
929-
String packageName = packageSep > 0 ? className.substring(0, packageSep) : "";
930-
synchronized (packages) {
931-
EconomicSet<String> packageNames = packages.get(container);
932-
if (packageNames == null) {
933-
packageNames = EconomicSet.create();
934-
packages.put(container, packageNames);
946+
int packageSep = className.lastIndexOf('.');
947+
String packageName = packageSep > 0 ? className.substring(0, packageSep) : "";
948+
synchronized (packages) {
949+
EconomicSet<String> packageNames = packages.get(container);
950+
if (packageNames == null) {
951+
packageNames = EconomicSet.create();
952+
packages.put(container, packageNames);
953+
}
954+
packageNames.add(packageName);
935955
}
936-
packageNames.add(packageName);
937956
}
938957

939958
Class<?> clazz = null;
@@ -945,10 +964,14 @@ private void handleClassFileName(URI container, Module module, String className,
945964
ImageClassLoader.handleClassLoadingError(t);
946965
}
947966
if (clazz != null) {
948-
if (includeUnconditionally) {
967+
String packageName = clazz.getPackageName();
968+
includedJavaPackages.add(packageName);
969+
if (includeUnconditionally || javaPackagesToInclude.contains(packageName)) {
949970
classesToIncludeUnconditionally.add(clazz);
950971
}
951-
imageClassLoader.handleClass(clazz);
972+
if (classRequiresInit) {
973+
imageClassLoader.handleClass(clazz);
974+
}
952975
}
953976
imageClassLoader.watchdog.recordActivity();
954977
}

0 commit comments

Comments
 (0)