24
24
*/
25
25
package com .oracle .svm .core ;
26
26
27
+ import java .util .Collections ;
28
+ import java .util .LinkedHashSet ;
27
29
import java .util .Objects ;
28
30
import java .util .Set ;
29
31
30
- import org .graalvm .collections . EconomicSet ;
32
+ import org .graalvm .nativeimage . ImageInfo ;
31
33
import org .graalvm .nativeimage .Platform ;
32
34
import org .graalvm .nativeimage .Platforms ;
33
35
42
44
import jdk .graal .compiler .options .OptionType ;
43
45
44
46
/**
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
47
55
* 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>.
48
60
*/
49
61
public class FutureDefaultsOptions {
50
62
private static final String OPTION_NAME = "future-defaults" ;
@@ -57,26 +69,36 @@ public class FutureDefaultsOptions {
57
69
58
70
public static final String RUN_TIME_INITIALIZE_JDK_REASON = "Initialize JDK classes at run time (--" + OPTION_NAME + " includes " + RUN_TIME_INITIALIZE_JDK_NAME + ")" ;
59
71
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 );
61
76
62
77
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 ;
64
86
}
65
87
66
88
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" ;
68
90
}
69
91
70
92
@ APIOption (name = OPTION_NAME , defaultValue = DEFAULT_NAME ) //
71
93
@ Option (help = "file:doc-files/FutureDefaultsHelp.txt" , type = OptionType .User ) //
72
94
static final HostedOptionKey <AccumulatingLocatableMultiOptionValue .Strings > FutureDefaults = new HostedOptionKey <>(
73
95
AccumulatingLocatableMultiOptionValue .Strings .buildWithCommaDelimiter ());
74
96
75
- private static EconomicSet <String > futureDefaults ;
97
+ private static Set <String > futureDefaults ;
76
98
77
99
@ Platforms (Platform .HOSTED_ONLY .class )
78
100
public static void parseAndVerifyOptions () {
79
- futureDefaults = EconomicSet . create ( ALL_VALUES .size ());
101
+ futureDefaults = new LinkedHashSet <>( getAllValues () .size ());
80
102
var valuesWithOrigin = FutureDefaults .getValue ().getValuesWithOrigins ();
81
103
valuesWithOrigin .forEach (valueWithOrigin -> {
82
104
String value = valueWithOrigin .value ();
@@ -87,7 +109,7 @@ public static void parseAndVerifyOptions() {
87
109
futureDefaultsAllValues ());
88
110
}
89
111
90
- if (!ALL_VALUES .contains (value )) {
112
+ if (!getAllValues () .contains (value )) {
91
113
throw UserError .abort ("The '%s' option from %s contains invalid value '%s'. It can only contain: %s." ,
92
114
SubstrateOptionsParser .commandArgument (FutureDefaults , value ),
93
115
valueWithOrigin .origin (),
@@ -104,23 +126,32 @@ public static void parseAndVerifyOptions() {
104
126
futureDefaults .clear ();
105
127
}
106
128
107
- futureDefaults .add (value );
129
+ if (value .equals (ALL_NAME )) {
130
+ futureDefaults .addAll (ALL_FUTURE_DEFAULTS );
131
+ } else {
132
+ futureDefaults .add (value );
133
+ }
108
134
});
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
+ }
109
140
}
110
141
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" ) );
113
144
}
114
145
115
146
public static boolean allFutureDefaults () {
116
- return getFutureDefaults ().contains ( ALL_NAME );
147
+ return getFutureDefaults ().containsAll ( ALL_FUTURE_DEFAULTS );
117
148
}
118
149
119
150
public static boolean isJDKInitializedAtRunTime () {
120
- return allFutureDefaults () || getFutureDefaults ().contains (RUN_TIME_INITIALIZE_JDK_NAME );
151
+ return getFutureDefaults ().contains (RUN_TIME_INITIALIZE_JDK_NAME );
121
152
}
122
153
123
154
public static boolean treatNameAsType () {
124
- return allFutureDefaults () || getFutureDefaults ().contains (TREAT_NAME_AS_TYPE_NAME );
155
+ return getFutureDefaults ().contains (TREAT_NAME_AS_TYPE_NAME );
125
156
}
126
157
}
0 commit comments