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));