2424 */
2525package com .oracle .svm .core ;
2626
27+ import java .util .Collections ;
28+ import java .util .LinkedHashSet ;
2729import java .util .Objects ;
2830import java .util .Set ;
2931
30- import org .graalvm .collections . EconomicSet ;
32+ import org .graalvm .nativeimage . ImageInfo ;
3133import org .graalvm .nativeimage .Platform ;
3234import org .graalvm .nativeimage .Platforms ;
3335
4244import jdk .graal .compiler .options .OptionType ;
4345
4446/**
45- * What makes it into the future-defaults must not be an experimental feature that can be rolled
46- * back. The changes must be aligning native image with the Java spec and must be thoroughly
47+ * Enables the --future-defaults=value flag that is used for evolution of Native Image semantics.
48+ * Each enabled future default also sets a build-time, and run-time property named
49+ * <code>'{@value #SYSTEM_PROPERTY_PREFIX}{@literal <property-name>}'</code> to <code>true</code>.
50+ * That property can be used by the community to adjust their code to work both with the previous
51+ * and with the new behavior of Native Image.
52+ * </p>
53+ * Note 1: What makes it into the future-defaults must not be an experimental feature that can be
54+ * rolled back. The changes must be aligning native image with the Java spec and must be thoroughly
4755 * reviewed.
56+ * </p>
57+ * Note 2: future defaults can not be simply removed as user code can depend on the system property
58+ * values that are set by the option. When removing a future-default option, one has to leave the
59+ * system property both a build time and at run time set to <code>true</code>.
4860 */
4961public class FutureDefaultsOptions {
5062 private static final String OPTION_NAME = "future-defaults" ;
@@ -57,26 +69,36 @@ public class FutureDefaultsOptions {
5769
5870 public static final String RUN_TIME_INITIALIZE_JDK_REASON = "Initialize JDK classes at run time (--" + OPTION_NAME + " includes " + RUN_TIME_INITIALIZE_JDK_NAME + ")" ;
5971
60- private static final Set <String > ALL_VALUES = Set .of (RUN_TIME_INITIALIZE_JDK_NAME , TREAT_NAME_AS_TYPE_NAME , ALL_NAME , NONE_NAME );
72+ public static final String SYSTEM_PROPERTY_PREFIX = ImageInfo .PROPERTY_NATIVE_IMAGE_PREFIX + OPTION_NAME + "." ;
73+
74+ private static final Set <String > ALL_FUTURE_DEFAULTS = Set .of (RUN_TIME_INITIALIZE_JDK_NAME , TREAT_NAME_AS_TYPE_NAME );
75+ private static final Set <String > ALL_COMMANDS = Set .of (ALL_NAME , NONE_NAME );
6176
6277 private static String futureDefaultsAllValues () {
63- return StringUtil .joinSingleQuoted (ALL_VALUES );
78+ return StringUtil .joinSingleQuoted (getAllValues ());
79+ }
80+
81+ private static Set <String > getAllValues () {
82+ Set <String > result = new LinkedHashSet <>(ALL_FUTURE_DEFAULTS .size () + ALL_COMMANDS .size ());
83+ result .addAll (ALL_FUTURE_DEFAULTS );
84+ result .addAll (ALL_COMMANDS );
85+ return result ;
6486 }
6587
6688 static {
67- assert ALL_VALUES .stream ().allMatch (futureDefaultsAllValues ()::contains ) : "A value is missing in the user-facing help text" ;
89+ assert getAllValues () .stream ().allMatch (futureDefaultsAllValues ()::contains ) : "A value is missing in the user-facing help text" ;
6890 }
6991
7092 @ APIOption (name = OPTION_NAME , defaultValue = DEFAULT_NAME ) //
7193 @ Option (help = "file:doc-files/FutureDefaultsHelp.txt" , type = OptionType .User ) //
7294 static final HostedOptionKey <AccumulatingLocatableMultiOptionValue .Strings > FutureDefaults = new HostedOptionKey <>(
7395 AccumulatingLocatableMultiOptionValue .Strings .buildWithCommaDelimiter ());
7496
75- private static EconomicSet <String > futureDefaults ;
97+ private static Set <String > futureDefaults ;
7698
7799 @ Platforms (Platform .HOSTED_ONLY .class )
78100 public static void parseAndVerifyOptions () {
79- futureDefaults = EconomicSet . create ( ALL_VALUES .size ());
101+ futureDefaults = new LinkedHashSet <>( getAllValues () .size ());
80102 var valuesWithOrigin = FutureDefaults .getValue ().getValuesWithOrigins ();
81103 valuesWithOrigin .forEach (valueWithOrigin -> {
82104 String value = valueWithOrigin .value ();
@@ -87,7 +109,7 @@ public static void parseAndVerifyOptions() {
87109 futureDefaultsAllValues ());
88110 }
89111
90- if (!ALL_VALUES .contains (value )) {
112+ if (!getAllValues () .contains (value )) {
91113 throw UserError .abort ("The '%s' option from %s contains invalid value '%s'. It can only contain: %s." ,
92114 SubstrateOptionsParser .commandArgument (FutureDefaults , value ),
93115 valueWithOrigin .origin (),
@@ -104,23 +126,32 @@ public static void parseAndVerifyOptions() {
104126 futureDefaults .clear ();
105127 }
106128
107- futureDefaults .add (value );
129+ if (value .equals (ALL_NAME )) {
130+ futureDefaults .addAll (ALL_FUTURE_DEFAULTS );
131+ } else {
132+ futureDefaults .add (value );
133+ }
108134 });
135+
136+ /* Set build-time properties for user features */
137+ for (String futureDefault : getFutureDefaults ()) {
138+ System .setProperty (FutureDefaultsOptions .SYSTEM_PROPERTY_PREFIX + futureDefault , Boolean .TRUE .toString ());
139+ }
109140 }
110141
111- private static EconomicSet <String > getFutureDefaults () {
112- return Objects .requireNonNull (futureDefaults , "must be initialized before usage" );
142+ public static Set <String > getFutureDefaults () {
143+ return Collections . unmodifiableSet ( Objects .requireNonNull (futureDefaults , "must be initialized before usage" ) );
113144 }
114145
115146 public static boolean allFutureDefaults () {
116- return getFutureDefaults ().contains ( ALL_NAME );
147+ return getFutureDefaults ().containsAll ( ALL_FUTURE_DEFAULTS );
117148 }
118149
119150 public static boolean isJDKInitializedAtRunTime () {
120- return allFutureDefaults () || getFutureDefaults ().contains (RUN_TIME_INITIALIZE_JDK_NAME );
151+ return getFutureDefaults ().contains (RUN_TIME_INITIALIZE_JDK_NAME );
121152 }
122153
123154 public static boolean treatNameAsType () {
124- return allFutureDefaults () || getFutureDefaults ().contains (TREAT_NAME_AS_TYPE_NAME );
155+ return getFutureDefaults ().contains (TREAT_NAME_AS_TYPE_NAME );
125156 }
126157}
0 commit comments