Skip to content

Commit 850d001

Browse files
committed
Flag that enables future behavoir for Native Image
1 parent da5502b commit 850d001

File tree

6 files changed

+128
-8
lines changed

6 files changed

+128
-8
lines changed

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeClassInitializationSupport.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -67,4 +67,11 @@ default void rerunInitialization(Class<?> aClass, String reason) {
6767
}
6868

6969
void initializeAtBuildTime(Class<?> aClass, String reason);
70+
71+
/**
72+
* Returns if the <code>className</code> was marked for build-time initialization. The result
73+
* applies both if a package prefix or a fully-qualified class name were configured as build
74+
* time.
75+
*/
76+
boolean isMarkedForBuildTimeInitialization(String className);
7077
}

substratevm/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ 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|jdk-at-run-time]` that allows for gentle migration to the future default behaviors of Native Image. The first enable behavior is `jdk-at-run-time` that moves away from build-time initialization of the JDK.
1415

1516
## GraalVM for JDK 24 (Internal Version 24.2.0)
1617
* (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

+68-6
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
import java.nio.file.Path;
3737
import java.nio.file.Paths;
3838
import java.util.List;
39+
import java.util.Set;
3940
import java.util.UUID;
4041
import java.util.function.Predicate;
4142

4243
import org.graalvm.collections.EconomicMap;
44+
import org.graalvm.collections.EconomicSet;
4345
import org.graalvm.collections.UnmodifiableEconomicMap;
4446
import org.graalvm.nativeimage.ImageInfo;
4547
import org.graalvm.nativeimage.ImageSingletons;
@@ -166,9 +168,7 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean o
166168
@Override
167169
public String getValueOrDefault(UnmodifiableEconomicMap<OptionKey<?>, Object> values) {
168170
if (!values.containsKey(this)) {
169-
return Platform.includedIn(Platform.ANDROID.class)
170-
? "bionic"
171-
: System.getProperty("substratevm.HostLibC", "glibc");
171+
return Platform.includedIn(Platform.ANDROID.class) ? "bionic" : System.getProperty("substratevm.HostLibC", "glibc");
172172
}
173173
return (String) values.get(this);
174174
}
@@ -884,9 +884,8 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, String ol
884884
isLLVMBackendMissing = ReflectionUtil.lookupClass(true, "com.oracle.svm.core.graal.llvm.LLVMFeature") == null;
885885
}
886886
if (isLLVMBackendMissing) {
887-
throw UserError.invalidOptionValue(CompilerBackend, newValue,
888-
"The LLVM backend for GraalVM Native Image is missing and needs to be built from source. " +
889-
"For instructions, please see https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/LLVMBackend.md.");
887+
throw UserError.invalidOptionValue(CompilerBackend, newValue, "The LLVM backend for GraalVM Native Image is missing and needs to be built from source. " +
888+
"For instructions, please see https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/LLVMBackend.md.");
890889
}
891890

892891
/* See GR-14405, https://github.com/oracle/graal/issues/1056 */
@@ -1277,6 +1276,10 @@ public Boolean getValueOrDefault(UnmodifiableEconomicMap<OptionKey<?>, Object> v
12771276
deprecated = true, deprecationMessage = "This option was introduced to simplify migration to GraalVM 23.0 and will be removed in a future release")//
12781277
public static final HostedOptionKey<Boolean> AllowDeprecatedBuilderClassesOnImageClasspath = new HostedOptionKey<>(false);
12791278

1279+
@Option(help = "Initialize JDK classes at build time the same way it was done before GraalVM 25.", type = OptionType.Debug, //
1280+
deprecated = true, deprecationMessage = "This option was introduced to simplify migration to GraalVM 25 and will be removed in a future release")//
1281+
public static final HostedOptionKey<Boolean> InitializeJDKAtBuildTimeMigration = new HostedOptionKey<>(false);
1282+
12801283
@APIOption(name = "exact-reachability-metadata", defaultValue = "")//
12811284
@Option(help = "file:doc-files/ExactReachabilityMetadataHelp.txt")//
12821285
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> ThrowMissingRegistrationErrors = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
@@ -1381,4 +1384,63 @@ 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_ALL_NAME = "all";
1391+
private static final String FUTURE_DEFAULTS_NONE_NAME = "none";
1392+
private static final String FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME = "run-time-initialized-jdk";
1393+
1394+
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);
1395+
private static final String FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT = "'" + FUTURE_DEFAULTS_ALL_NAME + "'" +
1396+
", '" + FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME + "'" +
1397+
", or '" + FUTURE_DEFAULTS_NONE_NAME + "'";
1398+
1399+
static {
1400+
assert FUTURE_DEFAULTS_ALL_VALUES.stream().allMatch(FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT::contains) : "A value is missing in the user-facing help text";
1401+
}
1402+
1403+
@APIOption(name = FUTURE_DEFAULTS_OPTION, defaultValue = FUTURE_DEFAULTS_NONE_NAME) //
1404+
@Option(help = "Enable the future default behaviors for Native Image. Comma-separated list can contain " + FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT + ". " +
1405+
"For example: '--" + FUTURE_DEFAULTS_OPTION + "=" + FUTURE_DEFAULTS_ALL_NAME + "'.", type = OptionType.User) //
1406+
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> FutureDefaults = new HostedOptionKey<>(
1407+
AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter(),
1408+
SubstrateOptions::validateFutureDefaults) {
1409+
@Override
1410+
protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, AccumulatingLocatableMultiOptionValue.Strings oldValue, AccumulatingLocatableMultiOptionValue.Strings newValue) {
1411+
super.onValueUpdate(values, oldValue, newValue);
1412+
}
1413+
};
1414+
1415+
private static EconomicSet<String> futureDefaults;
1416+
1417+
@Platforms(Platform.HOSTED_ONLY.class)
1418+
public static void validateFutureDefaults(HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> optionKey) {
1419+
futureDefaults = EconomicSet.create(FUTURE_DEFAULTS_ALL_VALUES.size());
1420+
var valuesWithOrigin = optionKey.getValue().getValuesWithOrigins();
1421+
valuesWithOrigin.forEach(valueWithOrigin -> {
1422+
String value = valueWithOrigin.value();
1423+
if (!FUTURE_DEFAULTS_ALL_VALUES.contains(value)) {
1424+
throw UserError.abort("The '%s' option from %s contains invalid value '%s'. It can only contain: %s.",
1425+
SubstrateOptionsParser.commandArgument(FutureDefaults, value),
1426+
valueWithOrigin.origin(),
1427+
value,
1428+
FUTURE_DEFAULTS_ALLOWED_VALUES_TEXT);
1429+
}
1430+
if (value.equals(FUTURE_DEFAULTS_NONE_NAME)) {
1431+
if (!valueWithOrigin.origin().commandLineLike()) {
1432+
throw UserError.abort("The '%s' option can only be used from the command line. Detected usage from %s.",
1433+
SubstrateOptionsParser.commandArgument(FutureDefaults, FUTURE_DEFAULTS_NONE_NAME),
1434+
valueWithOrigin.origin());
1435+
}
1436+
futureDefaults.clear();
1437+
}
1438+
1439+
futureDefaults.add(value);
1440+
});
1441+
}
1442+
1443+
public boolean isJDKInitializedAtRunTime() {
1444+
return futureDefaults.contains(FUTURE_DEFAULTS_ALL_NAME) || futureDefaults.contains(FUTURE_DEFAULTS_RUN_TIME_INITIALIZE_JDK_NAME);
1445+
}
13841446
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,12 @@ private void checkImageHeapInstance(DuringAnalysisAccess access, Object obj, Obj
198198
msg += """
199199
If you are seeing this message after upgrading to a new GraalVM release, this means that some objects ended up in the image heap without their type being marked with --initialize-at-build-time.
200200
To fix this, include %s in your configuration. If the classes do not originate from your code, it is advised to update all library or framework dependencies to the latest version before addressing this error.
201+
If the classes originate from the JDK you can try to use %s to temporarily disable this error until the proper configuration is introduced for the project.
201202
"""
202203
.replaceAll("\n", System.lineSeparator())
203204
.formatted(SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, proxyOrLambda ? proxyLambdaInterfaceCSV : typeName,
204-
"initialize-at-build-time", true, false));
205+
"initialize-at-build-time", true, false),
206+
SubstrateOptionsParser.commandArgument(SubstrateOptions.InitializeJDKAtBuildTimeMigration, "+"));
205207

206208
msg += System.lineSeparator() + "The following detailed trace displays from which field in the code the object was reached.";
207209
throw new UnsupportedFeatureException(msg);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java

+5
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,11 @@ public void initializeAtBuildTime(String name, String reason) {
287287
}
288288
}
289289

290+
@Override
291+
public boolean isMarkedForBuildTimeInitialization(String className) {
292+
return InitKind.BUILD_TIME == classInitializationConfiguration.lookupKind(className).getLeft();
293+
}
294+
290295
static boolean isClassListedInStringOption(AccumulatingLocatableMultiOptionValue.Strings option, Class<?> clazz) {
291296
return option.values().contains(clazz.getName());
292297
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.hosted.jdk;
26+
27+
import static com.oracle.svm.core.SubstrateOptions.InitializeJDKAtBuildTimeMigration;
28+
29+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
30+
import com.oracle.svm.core.feature.InternalFeature;
31+
32+
@AutomaticallyRegisteredFeature
33+
public class JDKInitializationMigrationFeature implements InternalFeature {
34+
35+
@Override
36+
public void afterRegistration(AfterRegistrationAccess access) {
37+
// Checkstyle: stop
38+
if (InitializeJDKAtBuildTimeMigration.getValue()) {
39+
/* Place all excluded entries from JDKInitializationFeature here. */
40+
}
41+
// Checkstyle: resume
42+
}
43+
}

0 commit comments

Comments
 (0)