Skip to content

Commit 96d61a4

Browse files
committed
Flag for future default behavior of Native Image
1 parent da5502b commit 96d61a4

File tree

6 files changed

+103
-4
lines changed

6 files changed

+103
-4
lines changed

docs/reference-manual/native-image/BuildOutput.md

+6
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,12 @@ This feature is currently only available for code compiled by Graal for Linux AM
282282

283283
The build output may contain one or more of the following recommendations that help you get the best out of Native Image.
284284

285+
#### <a name="recommendation-futr"></a>`FUTR`: Use the Correct Semantics and Prepare for the Future Releases
286+
287+
Use `--future-defaults=all` to ensure that the executable aligns more closely with JVM semantics and to prepare for future GraalVM releases where this will become the default.
288+
This flag is unlikely to affect your program's behavior but guarantees that it adheres to the correct execution semantics.
289+
Additionally, it ensures that future GraalVM updates will not introduce unexpected changes to your program's behavior.
290+
285291
#### <a name="recommendation-awt"></a>`AWT`: Missing Reachability Metadata for Abstract Window Toolkit
286292

287293
The Native Image analysis has included classes from the [`java.awt` package](https://docs.oracle.com/en/java/javase/22/docs/api/java.desktop/java/awt/package-summary.html) but could not find any reachability metadata for it.

substratevm/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ This changelog summarizes major changes to GraalVM Native Image.
1111
* (GR-61492) The experimental JDWP option is now present in standard GraalVM builds.
1212
* (GR-55222) Enabled lazy deoptimization of runtime-compiled code, which reduces memory used for deoptimization. Can be turned off with `-H:-LazyDeoptimization`.
1313
* (GR-54953) Add the experimental option `-H:Preserve` that makes the program work correctly without providing reachability metadata. Correctness is achieved by preserving all classes, resources, and reflection metadata in the image. Usage: `-H:Preserve=[all|none|module=<module>|package=<package>|package=<package-wildcard>|path=<cp-entry>][,...]`.
14+
* (GR-49525) Introduced `--future-defaults=[all|<options>|none]` that allows for gentle migration to the future default behaviors of Native Image. The enabled behaviors are:
15+
1. `run-time-initialized-jdk` that moves away from build-time initialization of the JDK.
1416

1517
## GraalVM for JDK 24 (Internal Version 24.2.0)
1618
* (GR-59717) Added `DuringSetupAccess.registerObjectReachabilityHandler` to allow registering a callback that is executed when an object of a specified type is marked as reachable during heap scanning.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java

+78
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@
3636
import java.nio.file.Path;
3737
import java.nio.file.Paths;
3838
import java.util.List;
39+
import java.util.Objects;
40+
import java.util.Set;
3941
import java.util.UUID;
4042
import java.util.function.Predicate;
4143

4244
import org.graalvm.collections.EconomicMap;
45+
import org.graalvm.collections.EconomicSet;
4346
import org.graalvm.collections.UnmodifiableEconomicMap;
4447
import org.graalvm.nativeimage.ImageInfo;
4548
import org.graalvm.nativeimage.ImageSingletons;
@@ -1381,4 +1384,79 @@ public static class TruffleStableOptions {
13811384

13821385
@Option(help = "file:doc-files/LibGraalClassLoader.txt")//
13831386
public static final HostedOptionKey<String> LibGraalClassLoader = new HostedOptionKey<>("");
1387+
1388+
private static final String FUTURE_DEFAULTS_OPTION = "future-defaults";
1389+
1390+
private static final String FUTURE_DEFAULTS_DEFAULT_NAME = "<default-value>";
1391+
private static final String FUTURE_DEFAULTS_ALL_NAME = "all";
1392+
private static final String FUTURE_DEFAULTS_NONE_NAME = "none";
1393+
private static final String FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME = "run-time-initialized-jdk";
1394+
1395+
/**
1396+
* Note: what makes it into the future-defaults must not be an experimental feature that can be
1397+
* rolled back. The changes must be aligning native image with the Java spec and must be
1398+
* thoroughly reviewed.
1399+
*/
1400+
private static final Set<String> FUTURE_DEFAULTS_ALL_VALUES = Set.of(FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME, FUTURE_DEFAULTS_ALL_NAME, FUTURE_DEFAULTS_NONE_NAME);
1401+
private static final String FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT = "'" + FUTURE_DEFAULTS_ALL_NAME + "'" +
1402+
", '" + FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME + "'" +
1403+
", or '" + FUTURE_DEFAULTS_NONE_NAME + "'";
1404+
1405+
static {
1406+
assert FUTURE_DEFAULTS_ALL_VALUES.stream().allMatch(FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT::contains) : "A value is missing in the user-facing help text";
1407+
}
1408+
1409+
@APIOption(name = FUTURE_DEFAULTS_OPTION, defaultValue = FUTURE_DEFAULTS_DEFAULT_NAME) //
1410+
@Option(help = "Enable the future default behaviors for Native Image. Comma-separated list can contain " + FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT + ". " +
1411+
"For example: '--" + FUTURE_DEFAULTS_OPTION + "=" + FUTURE_DEFAULTS_ALL_NAME + "'.", type = OptionType.User) //
1412+
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> FutureDefaults = new HostedOptionKey<>(
1413+
AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
1414+
1415+
private static EconomicSet<String> futureDefaults;
1416+
1417+
@Platforms(Platform.HOSTED_ONLY.class)
1418+
public static void processFutureDefaults() {
1419+
futureDefaults = EconomicSet.create(FUTURE_DEFAULTS_ALL_VALUES.size());
1420+
var valuesWithOrigin = FutureDefaults.getValue().getValuesWithOrigins();
1421+
valuesWithOrigin.forEach(valueWithOrigin -> {
1422+
String value = valueWithOrigin.value();
1423+
if (FUTURE_DEFAULTS_DEFAULT_NAME.equals(value)) {
1424+
throw UserError.abort("The '%s' from %s is forbidden. It can only contain: %s.",
1425+
SubstrateOptionsParser.commandArgument(FutureDefaults, FUTURE_DEFAULTS_DEFAULT_NAME),
1426+
valueWithOrigin.origin(),
1427+
FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT);
1428+
}
1429+
1430+
if (!FUTURE_DEFAULTS_ALL_VALUES.contains(value)) {
1431+
throw UserError.abort("The '%s' option from %s contains invalid value '%s'. It can only contain: %s.",
1432+
SubstrateOptionsParser.commandArgument(FutureDefaults, value),
1433+
valueWithOrigin.origin(),
1434+
value,
1435+
FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT);
1436+
}
1437+
1438+
if (value.equals(FUTURE_DEFAULTS_NONE_NAME)) {
1439+
if (!valueWithOrigin.origin().commandLineLike()) {
1440+
throw UserError.abort("The '%s' option can only be used from the command line. Detected usage from %s.",
1441+
SubstrateOptionsParser.commandArgument(FutureDefaults, FUTURE_DEFAULTS_NONE_NAME),
1442+
valueWithOrigin.origin());
1443+
}
1444+
futureDefaults.clear();
1445+
}
1446+
1447+
futureDefaults.add(value);
1448+
});
1449+
}
1450+
1451+
private static EconomicSet<String> getFutureDefaults() {
1452+
return Objects.requireNonNull(futureDefaults, "must be initialized before usage");
1453+
}
1454+
1455+
public static boolean allFutureDefaults() {
1456+
return getFutureDefaults().contains(FUTURE_DEFAULTS_ALL_NAME);
1457+
}
1458+
1459+
public static boolean isJDKInitializedAtRunTime() {
1460+
return allFutureDefaults() || getFutureDefaults().contains(FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME);
1461+
}
13841462
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ protected void setupNativeImage(String imageName, OptionValues options, Map<Meth
919919

920920
ImageSingletons.add(SubstrateOptions.ReportingSupport.class, new SubstrateOptions.ReportingSupport(
921921
DiagnosticsMode.getValue() ? DiagnosticsDir.getValue().lastValue().get() : Path.of("reports")));
922-
922+
SubstrateOptions.processFutureDefaults();
923923
if (javaMainSupport != null) {
924924
ImageSingletons.add(JavaMainSupport.class, javaMainSupport);
925925
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterFeature.java

+5
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,17 @@ public void createAdditionalArtifactsOnSuccess(@SuppressWarnings("unused") Build
106106

107107
protected List<UserRecommendation> getRecommendations() {
108108
return List.of(// in order of appearance:
109+
new UserRecommendation("FUTR", "Use --future-defaults=all to prepare for future releases.", ProgressReporterFeature::recommendFutureDefaults),
109110
new UserRecommendation("AWT", "Use the tracing agent to collect metadata for AWT.", ProgressReporterFeature::recommendTraceAgentForAWT),
110111
new UserRecommendation("HOME", "To avoid errors, provide java.home to the app with '-Djava.home=<path>'.", AnalyzeJavaHomeAccessFeature.instance()::getJavaHomeUsed),
111112
new UserRecommendation("HEAP", "Set max heap for improved and more predictable memory usage.", () -> SubstrateGCOptions.MaxHeapSize.getValue() == 0),
112113
new UserRecommendation("CPU", "Enable more CPU features with '-march=native' for improved performance.", ProgressReporterFeature::recommendMArchNative));
113114
}
114115

116+
private static boolean recommendFutureDefaults() {
117+
return !SubstrateOptions.allFutureDefaults();
118+
}
119+
115120
private static boolean recommendMArchNative() {
116121
if (NativeImageOptions.MicroArchitecture.getValue() != null) {
117122
return false; // explicitly set by user

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;
3232

3333
import com.oracle.svm.core.ParsingReason;
34+
import com.oracle.svm.core.SubstrateOptions;
3435
import com.oracle.svm.core.TypeResult;
3536
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3637
import com.oracle.svm.core.feature.InternalFeature;
@@ -143,9 +144,16 @@ public void afterRegistration(AfterRegistrationAccess access) {
143144
rci.initializeAtBuildTime("java.awt.font.JavaAWTFontAccessImpl", "Required for sun.text.bidi.BidiBase.NumericShapings");
144145

145146
/* XML-related */
146-
rci.initializeAtBuildTime("com.sun.xml", JDK_CLASS_REASON);
147-
rci.initializeAtBuildTime("com.sun.org.apache", JDK_CLASS_REASON);
148-
rci.initializeAtBuildTime("com.sun.org.slf4j.internal", JDK_CLASS_REASON);
147+
if (SubstrateOptions.isJDKInitializedAtRunTime()) {
148+
// GR-50683 should remove this part
149+
rci.initializeAtBuildTime("com.sun.xml", JDK_CLASS_REASON);
150+
rci.initializeAtBuildTime("com.sun.org.apache", JDK_CLASS_REASON);
151+
rci.initializeAtBuildTime("com.sun.org.slf4j.internal", JDK_CLASS_REASON);
152+
} else {
153+
rci.initializeAtBuildTime("com.sun.xml", JDK_CLASS_REASON);
154+
rci.initializeAtBuildTime("com.sun.org.apache", JDK_CLASS_REASON);
155+
rci.initializeAtBuildTime("com.sun.org.slf4j.internal", JDK_CLASS_REASON);
156+
}
149157

150158
/* Security services */
151159
rci.initializeAtBuildTime("com.sun.crypto.provider", JDK_CLASS_REASON);

0 commit comments

Comments
 (0)