Skip to content

Commit 2f557dd

Browse files
[GR-63551] Improve build-time validation of Native Image options.
PullRequest: graal/20418
2 parents 4d134f3 + 3c18557 commit 2f557dd

File tree

6 files changed

+78
-53
lines changed

6 files changed

+78
-53
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@
3939
/** Common options that can be specified for both the serial and the epsilon GC. */
4040
public final class SerialAndEpsilonGCOptions {
4141
@Option(help = "The maximum heap size as percent of physical memory. Serial and epsilon GC only.", type = OptionType.User) //
42-
public static final RuntimeOptionKey<Integer> MaximumHeapSizePercent = new NotifyGCRuntimeOptionKey<>(80, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly);
42+
public static final RuntimeOptionKey<Integer> MaximumHeapSizePercent = new NotifyGCRuntimeOptionKey<>(80, SerialAndEpsilonGCOptions::validateSerialOrEpsilonRuntimeOption);
4343

4444
@Option(help = "The maximum size of the young generation as a percentage of the maximum heap size. Serial and epsilon GC only.", type = OptionType.User) //
45-
public static final RuntimeOptionKey<Integer> MaximumYoungGenerationSizePercent = new NotifyGCRuntimeOptionKey<>(10, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly);
45+
public static final RuntimeOptionKey<Integer> MaximumYoungGenerationSizePercent = new NotifyGCRuntimeOptionKey<>(10, SerialAndEpsilonGCOptions::validateSerialOrEpsilonRuntimeOption);
4646

4747
@Option(help = "The size of an aligned chunk. Serial and epsilon GC only.", type = OptionType.Expert) //
48-
public static final HostedOptionKey<Long> AlignedHeapChunkSize = new HostedOptionKey<>(512 * 1024L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly) {
48+
public static final HostedOptionKey<Long> AlignedHeapChunkSize = new HostedOptionKey<>(512 * 1024L, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption) {
4949
@Override
5050
protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Long oldValue, Long newValue) {
5151
int multiple = 4096;
@@ -58,25 +58,31 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Long oldV
5858
* fit in an aligned chunk.
5959
*/
6060
@Option(help = "The size at or above which an array will be allocated in its own unaligned chunk. Serial and epsilon GC only.", type = OptionType.Expert) //
61-
public static final HostedOptionKey<Long> LargeArrayThreshold = new HostedOptionKey<>(128 * 1024L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly);
61+
public static final HostedOptionKey<Long> LargeArrayThreshold = new HostedOptionKey<>(128 * 1024L, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption);
6262

6363
@Option(help = "Fill unused memory chunks with a sentinel value. Serial and epsilon GC only.", type = OptionType.Debug) //
64-
public static final HostedOptionKey<Boolean> ZapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly);
64+
public static final HostedOptionKey<Boolean> ZapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption);
6565

6666
@Option(help = "Before use, fill memory chunks with a sentinel value. Serial and epsilon GC only.", type = OptionType.Debug) //
67-
public static final HostedOptionKey<Boolean> ZapProducedHeapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly);
67+
public static final HostedOptionKey<Boolean> ZapProducedHeapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption);
6868

6969
@Option(help = "After use, Fill memory chunks with a sentinel value. Serial and epsilon GC only.", type = OptionType.Debug) //
70-
public static final HostedOptionKey<Boolean> ZapConsumedHeapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly);
70+
public static final HostedOptionKey<Boolean> ZapConsumedHeapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption);
7171

7272
@Option(help = "Number of bytes at the beginning of each heap chunk that are not used for payload data, i.e., can be freely used as metadata by the heap chunk provider. Serial and epsilon GC only.", type = OptionType.Debug) //
73-
public static final HostedOptionKey<Integer> HeapChunkHeaderPadding = new HostedOptionKey<>(0, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly);
73+
public static final HostedOptionKey<Integer> HeapChunkHeaderPadding = new HostedOptionKey<>(0, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption);
7474

7575
private SerialAndEpsilonGCOptions() {
7676
}
7777

78-
public static void serialOrEpsilonGCOnly(OptionKey<?> optionKey) {
79-
if (!SubstrateOptions.useSerialGC() && !SubstrateOptions.useEpsilonGC()) {
78+
public static void validateSerialOrEpsilonHostedOption(HostedOptionKey<?> optionKey) {
79+
if (optionKey.hasBeenSet() && !SubstrateOptions.useSerialGC() && !SubstrateOptions.useEpsilonGC()) {
80+
throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial ('--gc=serial') or the epsilon garbage collector ('--gc=epsilon').");
81+
}
82+
}
83+
84+
public static void validateSerialOrEpsilonRuntimeOption(RuntimeOptionKey<?> optionKey) {
85+
if (optionKey.hasBeenSet() && !SubstrateOptions.useSerialGC() && !SubstrateOptions.useEpsilonGC()) {
8086
throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial ('--gc=serial') or the epsilon garbage collector ('--gc=epsilon').");
8187
}
8288
}

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@
4343
/** Options that are only valid for the serial GC (and not for the epsilon GC). */
4444
public final class SerialGCOptions {
4545
@Option(help = "The garbage collection policy, either Adaptive (default) or BySpaceAndTime. Serial GC only.", type = OptionType.User)//
46-
public static final HostedOptionKey<String> InitialCollectionPolicy = new HostedOptionKey<>("Adaptive", SerialGCOptions::serialGCOnly);
46+
public static final HostedOptionKey<String> InitialCollectionPolicy = new HostedOptionKey<>("Adaptive", SerialGCOptions::validateSerialHostedOption);
4747

4848
@Option(help = "Percentage of total collection time that should be spent on young generation collections. Serial GC with collection policy 'BySpaceAndTime' only.", type = OptionType.User)//
49-
public static final RuntimeOptionKey<Integer> PercentTimeInIncrementalCollection = new RuntimeOptionKey<>(50, SerialGCOptions::serialGCOnly);
49+
public static final RuntimeOptionKey<Integer> PercentTimeInIncrementalCollection = new RuntimeOptionKey<>(50, SerialGCOptions::validateSerialRuntimeOption);
5050

5151
@Option(help = "The maximum free bytes reserved for allocations, in bytes (0 for automatic according to GC policy). Serial GC only.", type = OptionType.User)//
52-
public static final RuntimeOptionKey<Long> MaxHeapFree = new RuntimeOptionKey<>(0L, SerialGCOptions::serialGCOnly);
52+
public static final RuntimeOptionKey<Long> MaxHeapFree = new RuntimeOptionKey<>(0L, SerialGCOptions::validateSerialRuntimeOption);
5353

5454
@Option(help = "Maximum number of survivor spaces. Serial GC only.", type = OptionType.Expert) //
55-
public static final HostedOptionKey<Integer> MaxSurvivorSpaces = new HostedOptionKey<>(null, SerialGCOptions::serialGCOnly) {
55+
public static final HostedOptionKey<Integer> MaxSurvivorSpaces = new HostedOptionKey<>(null, SerialGCOptions::validateSerialHostedOption) {
5656
@Override
5757
public Integer getValueOrDefault(UnmodifiableEconomicMap<OptionKey<?>, Object> values) {
5858
Integer value = (Integer) values.get(this);
@@ -68,67 +68,67 @@ public Integer getValue(OptionValues values) {
6868
};
6969

7070
@Option(help = "Determines if a full GC collects the young generation separately or together with the old generation. Serial GC only.", type = OptionType.Expert) //
71-
public static final RuntimeOptionKey<Boolean> CollectYoungGenerationSeparately = new RuntimeOptionKey<>(null, SerialGCOptions::serialGCOnly);
71+
public static final RuntimeOptionKey<Boolean> CollectYoungGenerationSeparately = new RuntimeOptionKey<>(null, SerialGCOptions::validateSerialRuntimeOption);
7272

7373
@Option(help = "Enables card marking for image heap objects, which arranges them in chunks. Automatically enabled when supported. Serial GC only.", type = OptionType.Expert) //
74-
public static final HostedOptionKey<Boolean> ImageHeapCardMarking = new HostedOptionKey<>(null, SerialGCOptions::serialGCOnly);
74+
public static final HostedOptionKey<Boolean> ImageHeapCardMarking = new HostedOptionKey<>(null, SerialGCOptions::validateSerialHostedOption);
7575

7676
@Option(help = "This number of milliseconds multiplied by the free heap memory in MByte is the time span " +
7777
"for which a soft reference will keep its referent alive after its last access. Serial GC only.", type = OptionType.Expert) //
78-
public static final HostedOptionKey<Integer> SoftRefLRUPolicyMSPerMB = new HostedOptionKey<>(1000, SerialGCOptions::serialGCOnly);
78+
public static final HostedOptionKey<Integer> SoftRefLRUPolicyMSPerMB = new HostedOptionKey<>(1000, SerialGCOptions::validateSerialHostedOption);
7979

8080
@Option(help = "Print summary GC information after application main method returns. Serial GC only.", type = OptionType.Debug)//
81-
public static final RuntimeOptionKey<Boolean> PrintGCSummary = new RuntimeOptionKey<>(false, SerialGCOptions::serialGCOnly);
81+
public static final RuntimeOptionKey<Boolean> PrintGCSummary = new RuntimeOptionKey<>(false, SerialGCOptions::validateSerialRuntimeOption);
8282

8383
@Option(help = "Print the time for each of the phases of each collection, if +VerboseGC. Serial GC only.", type = OptionType.Debug)//
84-
public static final RuntimeOptionKey<Boolean> PrintGCTimes = new RuntimeOptionKey<>(false, SerialGCOptions::serialGCOnly);
84+
public static final RuntimeOptionKey<Boolean> PrintGCTimes = new RuntimeOptionKey<>(false, SerialGCOptions::validateSerialRuntimeOption);
8585

8686
@Option(help = "Verify the heap before doing a garbage collection if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)//
87-
public static final HostedOptionKey<Boolean> VerifyBeforeGC = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly);
87+
public static final HostedOptionKey<Boolean> VerifyBeforeGC = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption);
8888

8989
@Option(help = "Verify the heap during a garbage collection if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)//
90-
public static final HostedOptionKey<Boolean> VerifyDuringGC = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly);
90+
public static final HostedOptionKey<Boolean> VerifyDuringGC = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption);
9191

9292
@Option(help = "Verify the heap after doing a garbage collection if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)//
93-
public static final HostedOptionKey<Boolean> VerifyAfterGC = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly);
93+
public static final HostedOptionKey<Boolean> VerifyAfterGC = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption);
9494

9595
@Option(help = "Verify the remembered set if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)//
96-
public static final HostedOptionKey<Boolean> VerifyRememberedSet = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly);
96+
public static final HostedOptionKey<Boolean> VerifyRememberedSet = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption);
9797

9898
@Option(help = "Verify all object references if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)//
99-
public static final HostedOptionKey<Boolean> VerifyReferences = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly);
99+
public static final HostedOptionKey<Boolean> VerifyReferences = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption);
100100

101101
@Option(help = "Verify that object references point into valid heap chunks if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)//
102-
public static final HostedOptionKey<Boolean> VerifyReferencesPointIntoValidChunk = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly);
102+
public static final HostedOptionKey<Boolean> VerifyReferencesPointIntoValidChunk = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption);
103103

104104
@Option(help = "Verify write barriers. Serial GC only.", type = OptionType.Debug)//
105-
public static final HostedOptionKey<Boolean> VerifyWriteBarriers = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly);
105+
public static final HostedOptionKey<Boolean> VerifyWriteBarriers = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption);
106106

107107
@Option(help = "Trace heap chunks during collections, if +VerboseGC. Serial GC only.", type = OptionType.Debug) //
108-
public static final RuntimeOptionKey<Boolean> TraceHeapChunks = new RuntimeOptionKey<>(false, SerialGCOptions::serialGCOnly);
108+
public static final RuntimeOptionKey<Boolean> TraceHeapChunks = new RuntimeOptionKey<>(false, SerialGCOptions::validateSerialRuntimeOption);
109109

110110
@Option(help = "Develop demographics of the object references visited. Serial GC only.", type = OptionType.Debug)//
111-
public static final HostedOptionKey<Boolean> GreyToBlackObjRefDemographics = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly);
111+
public static final HostedOptionKey<Boolean> GreyToBlackObjRefDemographics = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption);
112112

113113
@Option(help = "Ignore the maximum heap size while in VM-internal code. Serial GC only.", type = OptionType.Expert)//
114-
public static final HostedOptionKey<Boolean> IgnoreMaxHeapSizeWhileInVMInternalCode = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly);
114+
public static final HostedOptionKey<Boolean> IgnoreMaxHeapSizeWhileInVMInternalCode = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption);
115115

116116
@Option(help = "Determines whether to always (if true) or never (if false) outline write barrier code to a separate function, " +
117117
"trading reduced image size for (potentially) worse performance. Serial GC only.", type = OptionType.Expert) //
118-
public static final HostedOptionKey<Boolean> OutlineWriteBarriers = new HostedOptionKey<>(null, SerialGCOptions::serialGCOnly);
118+
public static final HostedOptionKey<Boolean> OutlineWriteBarriers = new HostedOptionKey<>(null, SerialGCOptions::validateSerialHostedOption);
119119

120120
/** Query these options only through an appropriate method. */
121121
public static class ConcealedOptions {
122122
@Option(help = "Collect old generation by compacting in-place instead of copying. Serial GC only.", type = OptionType.Expert) //
123123
public static final HostedOptionKey<Boolean> CompactingOldGen = new HostedOptionKey<>(false, SerialGCOptions::validateCompactingOldGen);
124124

125125
@Option(help = "Determines if a remembered set is used, which is necessary for collecting the young and old generation independently. Serial GC only.", type = OptionType.Expert) //
126-
public static final HostedOptionKey<Boolean> UseRememberedSet = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly);
126+
public static final HostedOptionKey<Boolean> UseRememberedSet = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption);
127127
}
128128

129129
public static class DeprecatedOptions {
130130
@Option(help = "Ignore the maximum heap size while in VM-internal code. Serial GC only.", type = OptionType.Expert, deprecated = true, deprecationMessage = "Please use the option 'IgnoreMaxHeapSizeWhileInVMInternalCode' instead.")//
131-
public static final HostedOptionKey<Boolean> IgnoreMaxHeapSizeWhileInVMOperation = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly) {
131+
public static final HostedOptionKey<Boolean> IgnoreMaxHeapSizeWhileInVMOperation = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption) {
132132
@Override
133133
protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean oldValue, Boolean newValue) {
134134
IgnoreMaxHeapSizeWhileInVMInternalCode.update(values, newValue);
@@ -139,8 +139,14 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean o
139139
private SerialGCOptions() {
140140
}
141141

142-
private static void serialGCOnly(OptionKey<?> optionKey) {
143-
if (!SubstrateOptions.useSerialGC()) {
142+
private static void validateSerialHostedOption(HostedOptionKey<?> optionKey) {
143+
if (optionKey.hasBeenSet() && !SubstrateOptions.useSerialGC()) {
144+
throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial garbage collector ('--gc=serial').");
145+
}
146+
}
147+
148+
private static void validateSerialRuntimeOption(RuntimeOptionKey<?> optionKey) {
149+
if (optionKey.hasBeenSet() && !SubstrateOptions.useSerialGC()) {
144150
throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial garbage collector ('--gc=serial').");
145151
}
146152
}
@@ -149,7 +155,7 @@ private static void validateCompactingOldGen(HostedOptionKey<Boolean> compacting
149155
if (!compactingOldGen.getValue()) {
150156
return;
151157
}
152-
serialGCOnly(compactingOldGen);
158+
validateSerialHostedOption(compactingOldGen);
153159
if (!useRememberedSet()) {
154160
throw UserError.abort("%s requires %s.", SubstrateOptionsParser.commandArgument(ConcealedOptions.CompactingOldGen, "+"),
155161
SubstrateOptionsParser.commandArgument(ConcealedOptions.UseRememberedSet, "+"));

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ private static boolean isPlatformSupported() {
109109
}
110110

111111
private static void validateSamplerOption(HostedOptionKey<Boolean> isSamplerEnabled) {
112-
if (isSamplerEnabled.getValue()) {
112+
if (isSamplerEnabled.hasBeenSet() && isSamplerEnabled.getValue()) {
113113
UserError.guarantee(isPlatformSupported(),
114114
"The %s cannot be used to profile on this platform.",
115115
SubstrateOptionsParser.commandArgument(isSamplerEnabled, "+"));

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,13 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean o
138138
@APIOption(name = "static")//
139139
@Option(help = "Build statically linked executable (requires static libc and zlib)")//
140140
public static final HostedOptionKey<Boolean> StaticExecutable = new HostedOptionKey<>(false, key -> {
141+
if (!key.getValue()) {
142+
return;
143+
}
144+
141145
if (!Platform.includedIn(Platform.LINUX.class)) {
142-
throw UserError.invalidOptionValue(key, key.getValue(), "Building static executable images is currently only supported on Linux. Remove the '--static' option or build on a Linux machine");
146+
throw UserError.invalidOptionValue(key, key.getValue(),
147+
"Building static executable images is currently only supported on Linux. Remove the '--static' option or build on a Linux machine");
143148
}
144149
if (!LibCBase.targetLibCIs(MuslLibC.class)) {
145150
throw UserError.invalidOptionValue(key, key.getValue(),
@@ -1389,7 +1394,7 @@ public static class TruffleStableOptions {
13891394

13901395
@Option(help = "Enable fallback to mremap for initializing the image heap.")//
13911396
public static final HostedOptionKey<Boolean> MremapImageHeap = new HostedOptionKey<>(true, key -> {
1392-
if (!Platform.includedIn(Platform.LINUX.class)) {
1397+
if (key.hasBeenSet() && !Platform.includedIn(Platform.LINUX.class)) {
13931398
throw UserError.invalidOptionValue(key, key.getValue(), "Mapping the image heap with mremap() is only supported on Linux.");
13941399
}
13951400
});

0 commit comments

Comments
 (0)