diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java index 17a14a576a90..f9e2f9aa9982 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java @@ -39,13 +39,13 @@ /** Common options that can be specified for both the serial and the epsilon GC. */ public final class SerialAndEpsilonGCOptions { @Option(help = "The maximum heap size as percent of physical memory. Serial and epsilon GC only.", type = OptionType.User) // - public static final RuntimeOptionKey MaximumHeapSizePercent = new NotifyGCRuntimeOptionKey<>(80, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); + public static final RuntimeOptionKey MaximumHeapSizePercent = new NotifyGCRuntimeOptionKey<>(80, SerialAndEpsilonGCOptions::validateSerialOrEpsilonRuntimeOption); @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) // - public static final RuntimeOptionKey MaximumYoungGenerationSizePercent = new NotifyGCRuntimeOptionKey<>(10, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); + public static final RuntimeOptionKey MaximumYoungGenerationSizePercent = new NotifyGCRuntimeOptionKey<>(10, SerialAndEpsilonGCOptions::validateSerialOrEpsilonRuntimeOption); @Option(help = "The size of an aligned chunk. Serial and epsilon GC only.", type = OptionType.Expert) // - public static final HostedOptionKey AlignedHeapChunkSize = new HostedOptionKey<>(512 * 1024L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly) { + public static final HostedOptionKey AlignedHeapChunkSize = new HostedOptionKey<>(512 * 1024L, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption) { @Override protected void onValueUpdate(EconomicMap, Object> values, Long oldValue, Long newValue) { int multiple = 4096; @@ -58,25 +58,31 @@ protected void onValueUpdate(EconomicMap, Object> values, Long oldV * fit in an aligned chunk. */ @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) // - public static final HostedOptionKey LargeArrayThreshold = new HostedOptionKey<>(128 * 1024L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); + public static final HostedOptionKey LargeArrayThreshold = new HostedOptionKey<>(128 * 1024L, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption); @Option(help = "Fill unused memory chunks with a sentinel value. Serial and epsilon GC only.", type = OptionType.Debug) // - public static final HostedOptionKey ZapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); + public static final HostedOptionKey ZapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption); @Option(help = "Before use, fill memory chunks with a sentinel value. Serial and epsilon GC only.", type = OptionType.Debug) // - public static final HostedOptionKey ZapProducedHeapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); + public static final HostedOptionKey ZapProducedHeapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption); @Option(help = "After use, Fill memory chunks with a sentinel value. Serial and epsilon GC only.", type = OptionType.Debug) // - public static final HostedOptionKey ZapConsumedHeapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); + public static final HostedOptionKey ZapConsumedHeapChunks = new HostedOptionKey<>(false, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption); @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) // - public static final HostedOptionKey HeapChunkHeaderPadding = new HostedOptionKey<>(0, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); + public static final HostedOptionKey HeapChunkHeaderPadding = new HostedOptionKey<>(0, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption); private SerialAndEpsilonGCOptions() { } - public static void serialOrEpsilonGCOnly(OptionKey optionKey) { - if (!SubstrateOptions.useSerialGC() && !SubstrateOptions.useEpsilonGC()) { + public static void validateSerialOrEpsilonHostedOption(HostedOptionKey optionKey) { + if (optionKey.hasBeenSet() && !SubstrateOptions.useSerialGC() && !SubstrateOptions.useEpsilonGC()) { + throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial ('--gc=serial') or the epsilon garbage collector ('--gc=epsilon')."); + } + } + + public static void validateSerialOrEpsilonRuntimeOption(RuntimeOptionKey optionKey) { + if (optionKey.hasBeenSet() && !SubstrateOptions.useSerialGC() && !SubstrateOptions.useEpsilonGC()) { throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial ('--gc=serial') or the epsilon garbage collector ('--gc=epsilon')."); } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java index b1c3fee4d365..7ed426612a84 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java @@ -43,16 +43,16 @@ /** Options that are only valid for the serial GC (and not for the epsilon GC). */ public final class SerialGCOptions { @Option(help = "The garbage collection policy, either Adaptive (default) or BySpaceAndTime. Serial GC only.", type = OptionType.User)// - public static final HostedOptionKey InitialCollectionPolicy = new HostedOptionKey<>("Adaptive", SerialGCOptions::serialGCOnly); + public static final HostedOptionKey InitialCollectionPolicy = new HostedOptionKey<>("Adaptive", SerialGCOptions::validateSerialHostedOption); @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)// - public static final RuntimeOptionKey PercentTimeInIncrementalCollection = new RuntimeOptionKey<>(50, SerialGCOptions::serialGCOnly); + public static final RuntimeOptionKey PercentTimeInIncrementalCollection = new RuntimeOptionKey<>(50, SerialGCOptions::validateSerialRuntimeOption); @Option(help = "The maximum free bytes reserved for allocations, in bytes (0 for automatic according to GC policy). Serial GC only.", type = OptionType.User)// - public static final RuntimeOptionKey MaxHeapFree = new RuntimeOptionKey<>(0L, SerialGCOptions::serialGCOnly); + public static final RuntimeOptionKey MaxHeapFree = new RuntimeOptionKey<>(0L, SerialGCOptions::validateSerialRuntimeOption); @Option(help = "Maximum number of survivor spaces. Serial GC only.", type = OptionType.Expert) // - public static final HostedOptionKey MaxSurvivorSpaces = new HostedOptionKey<>(null, SerialGCOptions::serialGCOnly) { + public static final HostedOptionKey MaxSurvivorSpaces = new HostedOptionKey<>(null, SerialGCOptions::validateSerialHostedOption) { @Override public Integer getValueOrDefault(UnmodifiableEconomicMap, Object> values) { Integer value = (Integer) values.get(this); @@ -68,54 +68,54 @@ public Integer getValue(OptionValues values) { }; @Option(help = "Determines if a full GC collects the young generation separately or together with the old generation. Serial GC only.", type = OptionType.Expert) // - public static final RuntimeOptionKey CollectYoungGenerationSeparately = new RuntimeOptionKey<>(null, SerialGCOptions::serialGCOnly); + public static final RuntimeOptionKey CollectYoungGenerationSeparately = new RuntimeOptionKey<>(null, SerialGCOptions::validateSerialRuntimeOption); @Option(help = "Enables card marking for image heap objects, which arranges them in chunks. Automatically enabled when supported. Serial GC only.", type = OptionType.Expert) // - public static final HostedOptionKey ImageHeapCardMarking = new HostedOptionKey<>(null, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey ImageHeapCardMarking = new HostedOptionKey<>(null, SerialGCOptions::validateSerialHostedOption); @Option(help = "This number of milliseconds multiplied by the free heap memory in MByte is the time span " + "for which a soft reference will keep its referent alive after its last access. Serial GC only.", type = OptionType.Expert) // - public static final HostedOptionKey SoftRefLRUPolicyMSPerMB = new HostedOptionKey<>(1000, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey SoftRefLRUPolicyMSPerMB = new HostedOptionKey<>(1000, SerialGCOptions::validateSerialHostedOption); @Option(help = "Print summary GC information after application main method returns. Serial GC only.", type = OptionType.Debug)// - public static final RuntimeOptionKey PrintGCSummary = new RuntimeOptionKey<>(false, SerialGCOptions::serialGCOnly); + public static final RuntimeOptionKey PrintGCSummary = new RuntimeOptionKey<>(false, SerialGCOptions::validateSerialRuntimeOption); @Option(help = "Print the time for each of the phases of each collection, if +VerboseGC. Serial GC only.", type = OptionType.Debug)// - public static final RuntimeOptionKey PrintGCTimes = new RuntimeOptionKey<>(false, SerialGCOptions::serialGCOnly); + public static final RuntimeOptionKey PrintGCTimes = new RuntimeOptionKey<>(false, SerialGCOptions::validateSerialRuntimeOption); @Option(help = "Verify the heap before doing a garbage collection if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)// - public static final HostedOptionKey VerifyBeforeGC = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey VerifyBeforeGC = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption); @Option(help = "Verify the heap during a garbage collection if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)// - public static final HostedOptionKey VerifyDuringGC = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey VerifyDuringGC = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption); @Option(help = "Verify the heap after doing a garbage collection if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)// - public static final HostedOptionKey VerifyAfterGC = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey VerifyAfterGC = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption); @Option(help = "Verify the remembered set if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)// - public static final HostedOptionKey VerifyRememberedSet = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey VerifyRememberedSet = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption); @Option(help = "Verify all object references if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)// - public static final HostedOptionKey VerifyReferences = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey VerifyReferences = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption); @Option(help = "Verify that object references point into valid heap chunks if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)// - public static final HostedOptionKey VerifyReferencesPointIntoValidChunk = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey VerifyReferencesPointIntoValidChunk = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption); @Option(help = "Verify write barriers. Serial GC only.", type = OptionType.Debug)// - public static final HostedOptionKey VerifyWriteBarriers = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey VerifyWriteBarriers = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption); @Option(help = "Trace heap chunks during collections, if +VerboseGC. Serial GC only.", type = OptionType.Debug) // - public static final RuntimeOptionKey TraceHeapChunks = new RuntimeOptionKey<>(false, SerialGCOptions::serialGCOnly); + public static final RuntimeOptionKey TraceHeapChunks = new RuntimeOptionKey<>(false, SerialGCOptions::validateSerialRuntimeOption); @Option(help = "Develop demographics of the object references visited. Serial GC only.", type = OptionType.Debug)// - public static final HostedOptionKey GreyToBlackObjRefDemographics = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey GreyToBlackObjRefDemographics = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption); @Option(help = "Ignore the maximum heap size while in VM-internal code. Serial GC only.", type = OptionType.Expert)// - public static final HostedOptionKey IgnoreMaxHeapSizeWhileInVMInternalCode = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey IgnoreMaxHeapSizeWhileInVMInternalCode = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption); @Option(help = "Determines whether to always (if true) or never (if false) outline write barrier code to a separate function, " + "trading reduced image size for (potentially) worse performance. Serial GC only.", type = OptionType.Expert) // - public static final HostedOptionKey OutlineWriteBarriers = new HostedOptionKey<>(null, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey OutlineWriteBarriers = new HostedOptionKey<>(null, SerialGCOptions::validateSerialHostedOption); /** Query these options only through an appropriate method. */ public static class ConcealedOptions { @@ -123,12 +123,12 @@ public static class ConcealedOptions { public static final HostedOptionKey CompactingOldGen = new HostedOptionKey<>(false, SerialGCOptions::validateCompactingOldGen); @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) // - public static final HostedOptionKey UseRememberedSet = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly); + public static final HostedOptionKey UseRememberedSet = new HostedOptionKey<>(true, SerialGCOptions::validateSerialHostedOption); } public static class DeprecatedOptions { @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.")// - public static final HostedOptionKey IgnoreMaxHeapSizeWhileInVMOperation = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly) { + public static final HostedOptionKey IgnoreMaxHeapSizeWhileInVMOperation = new HostedOptionKey<>(false, SerialGCOptions::validateSerialHostedOption) { @Override protected void onValueUpdate(EconomicMap, Object> values, Boolean oldValue, Boolean newValue) { IgnoreMaxHeapSizeWhileInVMInternalCode.update(values, newValue); @@ -139,8 +139,14 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o private SerialGCOptions() { } - private static void serialGCOnly(OptionKey optionKey) { - if (!SubstrateOptions.useSerialGC()) { + private static void validateSerialHostedOption(HostedOptionKey optionKey) { + if (optionKey.hasBeenSet() && !SubstrateOptions.useSerialGC()) { + throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial garbage collector ('--gc=serial')."); + } + } + + private static void validateSerialRuntimeOption(RuntimeOptionKey optionKey) { + if (optionKey.hasBeenSet() && !SubstrateOptions.useSerialGC()) { throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial garbage collector ('--gc=serial')."); } } @@ -149,7 +155,7 @@ private static void validateCompactingOldGen(HostedOptionKey compacting if (!compactingOldGen.getValue()) { return; } - serialGCOnly(compactingOldGen); + validateSerialHostedOption(compactingOldGen); if (!useRememberedSet()) { throw UserError.abort("%s requires %s.", SubstrateOptionsParser.commandArgument(ConcealedOptions.CompactingOldGen, "+"), SubstrateOptionsParser.commandArgument(ConcealedOptions.UseRememberedSet, "+")); diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java index 1ce33771f5cf..880e7dd52f34 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java @@ -109,7 +109,7 @@ private static boolean isPlatformSupported() { } private static void validateSamplerOption(HostedOptionKey isSamplerEnabled) { - if (isSamplerEnabled.getValue()) { + if (isSamplerEnabled.hasBeenSet() && isSamplerEnabled.getValue()) { UserError.guarantee(isPlatformSupported(), "The %s cannot be used to profile on this platform.", SubstrateOptionsParser.commandArgument(isSamplerEnabled, "+")); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index a93901cf413e..5d5f6650fe64 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -138,8 +138,13 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o @APIOption(name = "static")// @Option(help = "Build statically linked executable (requires static libc and zlib)")// public static final HostedOptionKey StaticExecutable = new HostedOptionKey<>(false, key -> { + if (!key.getValue()) { + return; + } + if (!Platform.includedIn(Platform.LINUX.class)) { - 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"); + 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"); } if (!LibCBase.targetLibCIs(MuslLibC.class)) { throw UserError.invalidOptionValue(key, key.getValue(), @@ -1383,7 +1388,7 @@ public static class TruffleStableOptions { @Option(help = "Enable fallback to mremap for initializing the image heap.")// public static final HostedOptionKey MremapImageHeap = new HostedOptionKey<>(true, key -> { - if (!Platform.includedIn(Platform.LINUX.class)) { + if (key.hasBeenSet() && !Platform.includedIn(Platform.LINUX.class)) { throw UserError.invalidOptionValue(key, key.getValue(), "Mapping the image heap with mremap() is only supported on Linux."); } }); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/ValidateImageBuildOptionsFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/BuildTimeOptionValidationFeature.java similarity index 65% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/ValidateImageBuildOptionsFeature.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/BuildTimeOptionValidationFeature.java index c20c7d1b8041..6a23ce4bd9e7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/ValidateImageBuildOptionsFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/BuildTimeOptionValidationFeature.java @@ -22,36 +22,36 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.option; - -import org.graalvm.collections.UnmodifiableMapCursor; +package com.oracle.svm.hosted.option; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.option.SubstrateOptionKey; +import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; -import jdk.graal.compiler.options.OptionKey; +import jdk.graal.compiler.options.OptionDescriptor; @AutomaticallyRegisteredFeature -public class ValidateImageBuildOptionsFeature implements InternalFeature { +public class BuildTimeOptionValidationFeature implements InternalFeature { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { - UnmodifiableMapCursor, Object> cursor = RuntimeOptionValues.singleton().getMap().getEntries(); + BeforeAnalysisAccessImpl a = (BeforeAnalysisAccessImpl) access; + HostedOptionParser optionParser = a.getImageClassLoader().classLoaderSupport.getHostedOptionParser(); + + var cursor = optionParser.getAllHostedOptions().getEntries(); while (cursor.advance()) { - validate(cursor.getKey()); + validate(cursor.getValue()); } - cursor = HostedOptionValues.singleton().getMap().getEntries(); + cursor = optionParser.getAllRuntimeOptions().getEntries(); while (cursor.advance()) { - validate(cursor.getKey()); + validate(cursor.getValue()); } } - private static void validate(OptionKey option) { - if (option instanceof SubstrateOptionKey) { - SubstrateOptionKey o = (SubstrateOptionKey) option; - if (o.hasBeenSet()) { - o.validate(); - } + private static void validate(OptionDescriptor desc) { + if (desc.getOptionKey() instanceof SubstrateOptionKey option) { + option.validate(); } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionParser.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionParser.java index 08fd39de5d86..3ce77140979f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionParser.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionParser.java @@ -133,6 +133,14 @@ public List getArguments() { return arguments; } + public EconomicMap getAllHostedOptions() { + return allHostedOptions; + } + + public EconomicMap getAllRuntimeOptions() { + return allRuntimeOptions; + } + @Override public EconomicMap, Object> getHostedValues() { return hostedValues;