diff --git a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest index d6c36f345076..738387fa4f50 100644 --- a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest +++ b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest @@ -160,6 +160,7 @@ fld public final static java.lang.String PROPERTY_IMAGE_CODE_VALUE_RUNTIME = "ru fld public final static java.lang.String PROPERTY_IMAGE_KIND_KEY = "org.graalvm.nativeimage.kind" fld public final static java.lang.String PROPERTY_IMAGE_KIND_VALUE_EXECUTABLE = "executable" fld public final static java.lang.String PROPERTY_IMAGE_KIND_VALUE_SHARED_LIBRARY = "shared" +fld public final static java.lang.String PROPERTY_NATIVE_IMAGE_PREFIX = "org.graalvm.nativeimage." meth public static boolean inImageBuildtimeCode() meth public static boolean inImageCode() meth public static boolean inImageRuntimeCode() diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java index efcafcf02764..cd14335226bf 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java @@ -54,6 +54,13 @@ public final class ImageInfo { private ImageInfo() { } + /** + * Holds a name that is a prefix for all native-image properties. + * + * @since 25.0 + */ + public static final String PROPERTY_NATIVE_IMAGE_PREFIX = "org.graalvm.nativeimage."; + /** * Holds the string that is the name of the system property providing information about the * context in which code is currently executing. If the property returns the string given by @@ -64,7 +71,7 @@ private ImageInfo() { * * @since 19.0 */ - public static final String PROPERTY_IMAGE_CODE_KEY = "org.graalvm.nativeimage.imagecode"; + public static final String PROPERTY_IMAGE_CODE_KEY = PROPERTY_NATIVE_IMAGE_PREFIX + "imagecode"; /** * Holds the string that will be returned by the system property for @@ -91,7 +98,7 @@ private ImageInfo() { * * @since 19.0 */ - public static final String PROPERTY_IMAGE_KIND_KEY = "org.graalvm.nativeimage.kind"; + public static final String PROPERTY_IMAGE_KIND_KEY = PROPERTY_NATIVE_IMAGE_PREFIX + "kind"; /** * Holds the string that will be returned by the system property for diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FutureDefaultsOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FutureDefaultsOptions.java index 1b6316095478..89f9a4a331a4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FutureDefaultsOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FutureDefaultsOptions.java @@ -24,10 +24,12 @@ */ package com.oracle.svm.core; +import java.util.Collections; +import java.util.LinkedHashSet; import java.util.Objects; import java.util.Set; -import org.graalvm.collections.EconomicSet; +import org.graalvm.nativeimage.ImageInfo; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -42,9 +44,19 @@ import jdk.graal.compiler.options.OptionType; /** - * What makes it into the future-defaults must not be an experimental feature that can be rolled - * back. The changes must be aligning native image with the Java spec and must be thoroughly + * Enables the --future-defaults=value flag that is used for evolution of Native Image semantics. + * Each enabled future default also sets a build-time, and run-time property named + * '{@value #SYSTEM_PROPERTY_PREFIX}{@literal }' to true. + * That property can be used by the community to adjust their code to work both with the previous + * and with the new behavior of Native Image. + *

+ * Note 1: What makes it into the future-defaults must not be an experimental feature that can be + * rolled back. The changes must be aligning native image with the Java spec and must be thoroughly * reviewed. + *

+ * Note 2: future defaults can not be simply removed as user code can depend on the system property + * values that are set by the option. When removing a future-default option, one has to leave the + * system property both a build time and at run time set to true. */ public class FutureDefaultsOptions { private static final String OPTION_NAME = "future-defaults"; @@ -57,14 +69,24 @@ public class FutureDefaultsOptions { public static final String RUN_TIME_INITIALIZE_JDK_REASON = "Initialize JDK classes at run time (--" + OPTION_NAME + " includes " + RUN_TIME_INITIALIZE_JDK_NAME + ")"; - private static final Set ALL_VALUES = Set.of(RUN_TIME_INITIALIZE_JDK_NAME, TREAT_NAME_AS_TYPE_NAME, ALL_NAME, NONE_NAME); + public static final String SYSTEM_PROPERTY_PREFIX = ImageInfo.PROPERTY_NATIVE_IMAGE_PREFIX + OPTION_NAME + "."; + + private static final Set ALL_FUTURE_DEFAULTS = Set.of(RUN_TIME_INITIALIZE_JDK_NAME, TREAT_NAME_AS_TYPE_NAME); + private static final Set ALL_COMMANDS = Set.of(ALL_NAME, NONE_NAME); private static String futureDefaultsAllValues() { - return StringUtil.joinSingleQuoted(ALL_VALUES); + return StringUtil.joinSingleQuoted(getAllValues()); + } + + private static Set getAllValues() { + Set result = new LinkedHashSet<>(ALL_FUTURE_DEFAULTS.size() + ALL_COMMANDS.size()); + result.addAll(ALL_FUTURE_DEFAULTS); + result.addAll(ALL_COMMANDS); + return result; } static { - assert ALL_VALUES.stream().allMatch(futureDefaultsAllValues()::contains) : "A value is missing in the user-facing help text"; + assert getAllValues().stream().allMatch(futureDefaultsAllValues()::contains) : "A value is missing in the user-facing help text"; } @APIOption(name = OPTION_NAME, defaultValue = DEFAULT_NAME) // @@ -72,11 +94,11 @@ private static String futureDefaultsAllValues() { static final HostedOptionKey FutureDefaults = new HostedOptionKey<>( AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); - private static EconomicSet futureDefaults; + private static Set futureDefaults; @Platforms(Platform.HOSTED_ONLY.class) public static void parseAndVerifyOptions() { - futureDefaults = EconomicSet.create(ALL_VALUES.size()); + futureDefaults = new LinkedHashSet<>(getAllValues().size()); var valuesWithOrigin = FutureDefaults.getValue().getValuesWithOrigins(); valuesWithOrigin.forEach(valueWithOrigin -> { String value = valueWithOrigin.value(); @@ -87,7 +109,7 @@ public static void parseAndVerifyOptions() { futureDefaultsAllValues()); } - if (!ALL_VALUES.contains(value)) { + if (!getAllValues().contains(value)) { throw UserError.abort("The '%s' option from %s contains invalid value '%s'. It can only contain: %s.", SubstrateOptionsParser.commandArgument(FutureDefaults, value), valueWithOrigin.origin(), @@ -104,23 +126,32 @@ public static void parseAndVerifyOptions() { futureDefaults.clear(); } - futureDefaults.add(value); + if (value.equals(ALL_NAME)) { + futureDefaults.addAll(ALL_FUTURE_DEFAULTS); + } else { + futureDefaults.add(value); + } }); + + /* Set build-time properties for user features */ + for (String futureDefault : getFutureDefaults()) { + System.setProperty(FutureDefaultsOptions.SYSTEM_PROPERTY_PREFIX + futureDefault, Boolean.TRUE.toString()); + } } - private static EconomicSet getFutureDefaults() { - return Objects.requireNonNull(futureDefaults, "must be initialized before usage"); + public static Set getFutureDefaults() { + return Collections.unmodifiableSet(Objects.requireNonNull(futureDefaults, "must be initialized before usage")); } public static boolean allFutureDefaults() { - return getFutureDefaults().contains(ALL_NAME); + return getFutureDefaults().containsAll(ALL_FUTURE_DEFAULTS); } public static boolean isJDKInitializedAtRunTime() { - return allFutureDefaults() || getFutureDefaults().contains(RUN_TIME_INITIALIZE_JDK_NAME); + return getFutureDefaults().contains(RUN_TIME_INITIALIZE_JDK_NAME); } public static boolean treatNameAsType() { - return allFutureDefaults() || getFutureDefaults().contains(TREAT_NAME_AS_TYPE_NAME); + return getFutureDefaults().contains(TREAT_NAME_AS_TYPE_NAME); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java index d1e1d3ab3010..1e3fe8cc631d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java @@ -43,6 +43,7 @@ import org.graalvm.nativeimage.hosted.RuntimeSystemProperties; import org.graalvm.nativeimage.impl.RuntimeSystemPropertiesSupport; +import com.oracle.svm.core.FutureDefaultsOptions; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.VM; @@ -143,6 +144,10 @@ protected SystemPropertiesSupport() { initializeProperty(ImageInfo.PROPERTY_IMAGE_CODE_KEY, ImageInfo.PROPERTY_IMAGE_CODE_VALUE_RUNTIME); + for (String futureDefault : FutureDefaultsOptions.getFutureDefaults()) { + initializeProperty(FutureDefaultsOptions.SYSTEM_PROPERTY_PREFIX + futureDefault, Boolean.TRUE.toString()); + } + ArrayList lazyProperties = new ArrayList<>(); lazyProperties.add(new LazySystemProperty(UserSystemProperty.NAME, this::userNameValue)); lazyProperties.add(new LazySystemProperty(UserSystemProperty.HOME, this::userHomeValue));