Skip to content

Commit 6487d3c

Browse files
committed
Implement package-wildcards for LayerCreate package suboption
Additionally provide a proper error message in case a package suboption does not lead to inclusion of classes.
1 parent 40f2aae commit 6487d3c

File tree

16 files changed

+329
-161
lines changed

16 files changed

+329
-161
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionsParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,12 @@
3838
import java.util.function.Function;
3939
import java.util.regex.Pattern;
4040

41-
import jdk.graal.compiler.core.common.LibGraalSupport;
4241
import org.graalvm.collections.EconomicMap;
4342
import org.graalvm.collections.EconomicSet;
4443
import org.graalvm.collections.MapCursor;
4544

45+
import jdk.graal.compiler.core.common.LibGraalSupport;
46+
4647
/**
4748
* This class contains methods for parsing Graal options and matching them against a set of
4849
* {@link OptionDescriptors}. The {@link OptionDescriptors} are loaded via a {@link ServiceLoader}.
@@ -343,6 +344,7 @@ public static boolean collectFuzzyMatches(Iterable<OptionDescriptor> toSearch, S
343344
* @param toSearch the entries search
344345
* @param name the name to search for
345346
* @param matches the collection to which fuzzy matches of {@code name} will be added
347+
* @param extractor functor that maps entry to String
346348
* @return whether any fuzzy matches were found
347349
*/
348350
public static <T> boolean collectFuzzyMatches(Iterable<T> toSearch, String name, Collection<T> matches, Function<T, String> extractor) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
/**
4343
* Policy used to determine which classes, methods and fields need to be included in the image when
44-
* the {@code IncludeAllFromPath} and/or {@code IncludeAllFromModule} options are specified
44+
* {@code LayerCreate} sub-options {@code module}, {@code package} or {@code path} are specified
4545
* depending on the configuration.
4646
*/
4747
public abstract class ClassInclusionPolicy {

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

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,23 +1313,9 @@ public enum ReportingMode {
13131313
@Option(help = "Deprecated, option no longer has any effect.", deprecated = true, deprecationMessage = "It no longer has any effect, and no replacement is available")//
13141314
public static final HostedOptionKey<Boolean> UseOldMethodHandleIntrinsics = new HostedOptionKey<>(false);
13151315

1316-
@Option(help = "Include all classes, methods, and fields from given modules", type = OptionType.Debug) //
1317-
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllFromModule = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
1318-
1319-
@Option(help = "Include all classes, methods, fields, and resources from given paths", type = OptionType.Debug) //
1320-
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllFromPath = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
1321-
1322-
@Option(help = "Include all classes, methods and fields from the given packages", type = OptionType.Debug) //
1323-
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeAllFromPackage = new HostedOptionKey<>(
1324-
AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
1325-
13261316
@Option(help = "Include all classes, methods, fields, and resources from the class path", type = OptionType.Debug) //
13271317
public static final HostedOptionKey<Boolean> IncludeAllFromClassPath = new HostedOptionKey<>(false);
13281318

1329-
public static boolean includeAll() {
1330-
return IncludeAllFromModule.hasBeenSet() || IncludeAllFromPath.hasBeenSet() || IncludeAllFromPackage.hasBeenSet() || IncludeAllFromClassPath.hasBeenSet();
1331-
}
1332-
13331319
@Option(help = "Force include include all public types and methods that can be reached using normal Java access rules.")//
13341320
public static final HostedOptionKey<Boolean> UseBaseLayerInclusionPolicy = new HostedOptionKey<>(false);
13351321

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/OptionOrigin.java

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,19 @@
2525

2626
package com.oracle.svm.core.option;
2727

28+
import java.io.BufferedReader;
2829
import java.io.FileNotFoundException;
2930
import java.io.IOException;
3031
import java.net.URI;
3132
import java.net.URISyntaxException;
3233
import java.nio.file.FileSystem;
34+
import java.nio.file.FileSystemNotFoundException;
3335
import java.nio.file.FileSystems;
3436
import java.nio.file.Files;
3537
import java.nio.file.Path;
36-
import java.util.Collections;
38+
import java.util.ArrayList;
3739
import java.util.List;
40+
import java.util.Map;
3841
import java.util.Objects;
3942

4043
import com.oracle.svm.core.option.OptionUtils.MacroOptionKind;
@@ -153,7 +156,20 @@ protected static URI originURI(String origin) {
153156

154157
static List<String> getRedirectionValuesFromPath(Path normalizedRedirPath) throws IOException {
155158
if (Files.isReadable(normalizedRedirPath)) {
156-
return Files.readAllLines(normalizedRedirPath);
159+
try (BufferedReader reader = Files.newBufferedReader(normalizedRedirPath)) {
160+
List<String> values = new ArrayList<>();
161+
while (true) {
162+
String line = reader.readLine();
163+
if (line == null) {
164+
break;
165+
}
166+
if (line.isEmpty() || line.startsWith("#")) {
167+
continue;
168+
}
169+
values.add(line);
170+
}
171+
return values;
172+
}
157173
}
158174
throw new FileNotFoundException("Unable to read file from " + normalizedRedirPath.toUri());
159175
}
@@ -338,17 +354,24 @@ protected JarOptionOrigin(boolean isStable, URI rawOrigin) {
338354
public List<String> getRedirectionValues(Path valuesFile) throws IOException {
339355
URI jarFileURI = URI.create("jar:" + container());
340356
FileSystem probeJarFS;
357+
boolean cleanup = false;
341358
try {
342-
probeJarFS = FileSystems.newFileSystem(jarFileURI, Collections.emptyMap());
343-
} catch (UnsupportedOperationException e) {
344-
probeJarFS = null;
359+
probeJarFS = FileSystems.getFileSystem(jarFileURI);
360+
} catch (FileSystemNotFoundException e) {
361+
probeJarFS = FileSystems.newFileSystem(jarFileURI, Map.of());
362+
cleanup = true;
345363
}
346364
if (probeJarFS == null) {
347365
throw new IOException("Unable to create jar file system for " + jarFileURI);
348366
}
349-
try (FileSystem fs = probeJarFS) {
367+
try {
350368
var normalizedRedirPath = location().getParent().resolve(valuesFile).normalize();
351-
return getRedirectionValuesFromPath(normalizedRedirPath);
369+
List<String> values = getRedirectionValuesFromPath(probeJarFS.getPath("/", normalizedRedirPath.toString()));
370+
return values;
371+
} finally {
372+
if (cleanup) {
373+
probeJarFS.close();
374+
}
352375
}
353376
}
354377
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/OptionUtils.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import java.util.stream.Stream;
3636

3737
import com.oracle.svm.core.SubstrateUtil;
38-
import com.oracle.svm.core.util.UserError;
38+
import com.oracle.svm.core.option.LocatableMultiOptionValue.ValueWithOrigin;
3939

4040
import jdk.graal.compiler.options.OptionDescriptor;
4141
import jdk.graal.compiler.options.OptionKey;
@@ -45,8 +45,12 @@
4545
*/
4646
public class OptionUtils {
4747

48+
public static List<String> resolveOptionValuesRedirection(OptionKey<?> option, ValueWithOrigin<String> valueWithOrigin) {
49+
return resolveOptionValuesRedirection(option, valueWithOrigin.value(), valueWithOrigin.origin());
50+
}
51+
4852
public static List<String> resolveOptionValuesRedirection(OptionKey<?> option, String optionValue, OptionOrigin origin) {
49-
return Arrays.asList(SubstrateUtil.split(optionValue, ",")).stream()
53+
return Arrays.stream(SubstrateUtil.split(optionValue, ","))
5054
.flatMap(entry -> resolveOptionValueRedirection(option, optionValue, origin, entry))
5155
.collect(Collectors.toList());
5256
}
@@ -55,14 +59,14 @@ private static Stream<? extends String> resolveOptionValueRedirection(OptionKey<
5559
if (entry.trim().startsWith("@")) {
5660
Path valuesFile = Path.of(entry.substring(1));
5761
if (valuesFile.isAbsolute()) {
58-
throw UserError.abort("Option '%s' provided by %s contains value redirection file '%s' that is an absolute path.",
59-
SubstrateOptionsParser.commandArgument(option, optionValue), origin, valuesFile);
62+
throw new AssertionError("Option '" + SubstrateOptionsParser.commandArgument(option, optionValue) + "' provided by " + origin +
63+
" contains value redirection file '" + valuesFile + "' that is an absolute path.");
6064
}
6165
try {
6266
return origin.getRedirectionValues(valuesFile).stream();
6367
} catch (IOException e) {
64-
throw UserError.abort(e, "Option '%s' provided by %s contains invalid option value redirection.",
65-
SubstrateOptionsParser.commandArgument(option, optionValue), origin);
68+
throw new AssertionError("Option '" + SubstrateOptionsParser.commandArgument(option, optionValue) + "' provided by " + origin +
69+
" contains invalid option value redirection.", e);
6670
}
6771
} else {
6872
return Stream.of(entry);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/SubstrateOptionsParser.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import com.oracle.svm.common.option.CommonOptionParser.OptionParseResult;
4242
import com.oracle.svm.common.option.UnsupportedOptionClassException;
4343
import com.oracle.svm.core.util.InterruptImageBuilding;
44-
import com.oracle.svm.core.util.VMError;
4544
import com.oracle.svm.util.LogUtils;
4645

4746
import jdk.graal.compiler.options.OptionDescriptor;
@@ -63,8 +62,7 @@ static OptionParseResult parseOption(EconomicMap<String, OptionDescriptor> optio
6362
try {
6463
return CommonOptionParser.parseOption(options, isHosted, option, valuesMap, optionPrefix, booleanOptionFormat);
6564
} catch (UnsupportedOptionClassException e) {
66-
VMError.shouldNotReachHere(e.getMessage());
67-
return null;
65+
throw new AssertionError("Should not reach here", e);
6866
}
6967
}
7068

@@ -160,7 +158,6 @@ public static double parseDouble(String v) {
160158
* @return recommendation for setting a option value (e.g., for option 'Name' and value 'file'
161159
* it returns "-H:Name=file")
162160
*/
163-
@Platforms(Platform.HOSTED_ONLY.class)
164161
public static String commandArgument(OptionKey<?> option, String value) {
165162
return commandArgument(option, value, null);
166163
}
@@ -175,7 +172,6 @@ public static String commandArgument(OptionKey<?> option, String value) {
175172
* @return recommendation for setting a option value (e.g., for option 'Name' and value 'file'
176173
* it returns "-H:Name=file")
177174
*/
178-
@Platforms(Platform.HOSTED_ONLY.class)
179175
public static String commandArgument(OptionKey<?> option, String value, String apiOptionName) {
180176
/* Ensure descriptor is loaded */
181177
OptionDescriptor optionDescriptor = option.loadDescriptor();
@@ -193,7 +189,9 @@ public static String commandArgument(OptionKey<?> option, String value, String a
193189
}
194190

195191
if (optionDescriptor.getOptionValueType() == Boolean.class) {
196-
VMError.guarantee(value.equals("+") || value.equals("-"), "Boolean option value can be only + or -");
192+
if (!value.equals("+") && !value.equals("-")) {
193+
throw new AssertionError("Boolean option value can be only + or -");
194+
}
197195
for (APIOption apiOption : apiOptions) {
198196
String selected = selectVariant(apiOption, apiOptionName);
199197
if (selected != null) {
@@ -240,12 +238,10 @@ public static String commandArgument(OptionKey<?> option, String value, String a
240238
}
241239
}
242240

243-
@Platforms(Platform.HOSTED_ONLY.class)
244241
public static String commandArgument(OptionKey<?> option, String value, String apiOptionName, boolean escape, boolean newLine) {
245242
return formatCommandArgument(commandArgument(option, value, apiOptionName), escape, newLine);
246243
}
247244

248-
@Platforms(Platform.HOSTED_ONLY.class)
249245
public static String commandArgument(OptionKey<?> option, String value, boolean escape, boolean newLine) {
250246
return formatCommandArgument(commandArgument(option, value), escape, newLine);
251247
}
@@ -262,7 +258,9 @@ private static String formatCommandArgument(String optionMessage, boolean escape
262258
}
263259

264260
private static String selectVariant(APIOption apiOption, String apiOptionName) {
265-
VMError.guarantee(apiOption.name().length > 0, "APIOption requires at least one name");
261+
if (apiOption.name().length <= 0) {
262+
throw new AssertionError("APIOption requires at least one name");
263+
}
266264
if (!apiOption.deprecated().equals("")) {
267265
return null; /* Never select deprecated API options. */
268266
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UserError.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@
4343
@SuppressWarnings("serial")
4444
public class UserError {
4545

46+
/**
47+
* Stop compilation immediately and report the message to the user.
48+
*
49+
* @param format format string (must not start with a lowercase letter)
50+
* @param args arguments for the format string that are {@link #formatArguments(Object...)
51+
* preprocessed} before being sent to {@link String#format(String, Object...)}
52+
*/
53+
public static UserException abort(String format, Object... args) {
54+
throw new UserException(String.format(format, formatArguments(args)));
55+
}
56+
4657
/**
4758
* UserException type for all errors that should be reported to the SVM users.
4859
*/
@@ -74,17 +85,6 @@ public Iterable<String> getMessages() {
7485
}
7586
}
7687

77-
/**
78-
* Stop compilation immediately and report the message to the user.
79-
*
80-
* @param format format string (must not start with a lowercase letter)
81-
* @param args arguments for the format string that are {@link #formatArguments(Object...)
82-
* preprocessed} before being sent to {@link String#format(String, Object...)}
83-
*/
84-
public static UserException abort(String format, Object... args) {
85-
throw new UserException(String.format(format, formatArguments(args)));
86-
}
87-
8888
/**
8989
* Stop compilation immediately and report the message to the user.
9090
*

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

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

34-
import com.oracle.svm.core.SubstrateOptions;
3534
import com.oracle.svm.core.VM;
3635
import com.oracle.svm.core.option.OptionOrigin;
3736
import com.oracle.svm.core.util.ExitStatus;
3837
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;
4238
import com.oracle.svm.util.LogUtils;
4339

4440
import jdk.graal.compiler.options.OptionType;
@@ -142,25 +138,6 @@ private boolean consume(ArgumentQueue args, String headArg) {
142138
return true;
143139
}
144140

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-
164141
if (headArg.startsWith(DEBUG_ATTACH_OPTION)) {
165142
if (useDebugAttach) {
166143
throw NativeImage.showError("The " + DEBUG_ATTACH_OPTION + " option can only be used once.");

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,15 @@
2828
import java.nio.file.Files;
2929
import java.nio.file.Path;
3030
import java.nio.file.Paths;
31+
import java.util.List;
3132

33+
import com.oracle.svm.core.SubstrateOptions;
3234
import com.oracle.svm.core.option.OptionOrigin;
35+
import com.oracle.svm.core.option.OptionUtils;
3336
import com.oracle.svm.driver.NativeImage.ArgumentQueue;
37+
import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.ExtendedOption;
38+
import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.LayerOption;
39+
import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.PackageOptionValue;
3440
import com.oracle.svm.util.LogUtils;
3541

3642
class DefaultOptionHandler extends NativeImage.OptionHandler<NativeImage> {
@@ -139,6 +145,32 @@ public boolean consume(ArgumentQueue args) {
139145
processClasspathArgs(cpArgs);
140146
return true;
141147
}
148+
if (headArg.startsWith(nativeImage.oHLayerCreate)) {
149+
String rawLayerCreateValue = headArg.substring(nativeImage.oHLayerCreate.length());
150+
if (!rawLayerCreateValue.isEmpty()) {
151+
List<String> layerCreateValue = OptionUtils.resolveOptionValuesRedirection(SubstrateOptions.LayerCreate, rawLayerCreateValue, OptionOrigin.from(args.argumentOrigin));
152+
LayerOption layerOption = LayerOption.parse(layerCreateValue);
153+
for (ExtendedOption option : layerOption.extendedOptions()) {
154+
var packageOptionValue = PackageOptionValue.from(option);
155+
if (packageOptionValue == null) {
156+
continue;
157+
}
158+
String packageName = packageOptionValue.name();
159+
if (packageOptionValue.isWildcard()) {
160+
nativeImage.systemPackagesToModules.forEach((systemPackageName, moduleName) -> {
161+
if (systemPackageName.startsWith(packageName)) {
162+
nativeImage.addAddedModules(moduleName);
163+
}
164+
});
165+
} else {
166+
String moduleName = nativeImage.systemPackagesToModules.get(packageName);
167+
if (moduleName != null) {
168+
nativeImage.addAddedModules(moduleName);
169+
}
170+
}
171+
}
172+
}
173+
}
142174
if (headArg.startsWith(NativeImage.oH)) {
143175
args.poll();
144176
nativeImage.addPlainImageBuilderArg(headArg, args.argumentOrigin);

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ private static <T> String oR(OptionKey<T> option) {
285285

286286
final String oHInspectServerContentPath = oH(PointstoOptions.InspectServerContentPath);
287287
final String oHDeadlockWatchdogInterval = oH(SubstrateOptions.DeadlockWatchdogInterval);
288+
final String oHLayerCreate = oH(SubstrateOptions.LayerCreate);
288289

289290
final Map<String, String> imageBuilderEnvironment = new HashMap<>();
290291
private final ArrayList<String> imageBuilderArgs = new ArrayList<>();
@@ -1338,6 +1339,10 @@ private int completeImageBuild() {
13381339
}
13391340
}
13401341

1342+
if (mainClass != null && !mainClass.isEmpty() && !Character.isJavaIdentifierStart(mainClass.charAt(0))) {
1343+
showError("'%s' is not a valid mainclass. Specify a valid classname for the class that contains the main method.".formatted(mainClass));
1344+
}
1345+
13411346
if (!extraImageArgs.isEmpty()) {
13421347
showError("Unrecognized option(s): " + StringUtil.joinSingleQuoted(extraImageArgs.stream().map(ArgumentEntry::value).toList()));
13431348
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public void loadAllClasses() throws InterruptedException {
9393
}
9494
}
9595
}
96-
classLoaderSupport.reportBuilderClassesInApplication();
96+
classLoaderSupport.allClassesLoaded();
9797
}
9898

9999
private void findSystemElements(Class<?> systemClass) {

0 commit comments

Comments
 (0)