Skip to content

Commit c38d527

Browse files
author
Christian Wimmer
committed
[GR-39406] Allow all classes to be used at image build time.
PullRequest: graal/12091
2 parents c6e1f85 + f3114f9 commit c38d527

File tree

8 files changed

+26
-17
lines changed

8 files changed

+26
-17
lines changed

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This changelog summarizes major changes to GraalVM Native Image.
77
* (GR-45841) BellSoft added support for the JFR event ThreadCPULoad.
88
* (GR-45994) Removed the option `-H:EnableSignalAPI`. Please use the runtime option `EnableSignalHandling` if it is necessary to enable or disable signal handling explicitly.
99
* (GR-39406) Simulation of class initializer: Class initializer of classes that are not marked for initialization at image build time are simulated at image build time to avoid executing them at image run time.
10+
* (GR-39406) All classes can now be used at image build time, even when they are not explicitly configured as `--initialize-at-build-time`. Note, however, that still only classes configured as `--initialize-at-build-time` are allowed in the image heap.
1011
* (GR-46392) Add `--parallelism` option to control how many threads are used by the build process.
1112
* (GR-46392) Add build resources section to the build output that shows the memory and thread limits of the build process.
1213

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,9 +1413,9 @@ def build_and_test_clinittest_image(native_image, args, new_class_init_policy):
14131413
mkpath(build_dir)
14141414

14151415
if new_class_init_policy:
1416-
policy_args = ['-H:+UseNewExperimentalClassInitialization', '-H:+SimulateClassInitializer', '-H:Features=com.oracle.svm.test.clinit.TestClassInitializationFeatureNewPolicyFeature']
1416+
policy_args = ['-H:-UseDeprecatedOldClassInitialization', '-H:+SimulateClassInitializer', '-H:Features=com.oracle.svm.test.clinit.TestClassInitializationFeatureNewPolicyFeature']
14171417
else:
1418-
policy_args = ['-H:-UseNewExperimentalClassInitialization', '-H:-SimulateClassInitializer', '-H:Features=com.oracle.svm.test.clinit.TestClassInitializationFeatureOldPolicyFeature']
1418+
policy_args = ['-H:+UseDeprecatedOldClassInitialization', '-H:-SimulateClassInitializer', '-H:Features=com.oracle.svm.test.clinit.TestClassInitializationFeatureOldPolicyFeature']
14191419

14201420
# Build and run the example
14211421
native_image(

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626

2727
import java.lang.reflect.Proxy;
2828

29-
import org.graalvm.compiler.java.LambdaUtils;
30-
3129
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
3230
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
3331
import com.oracle.svm.core.util.UserError;
@@ -161,8 +159,8 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize)
161159
}
162160
superResult = superResult.max(processInterfaces(clazz, memoize));
163161

164-
if (superResult == InitKind.BUILD_TIME && (Proxy.isProxyClass(clazz) || LambdaUtils.isLambdaType(metaAccess.lookupJavaType(clazz)))) {
165-
forceInitializeHosted(clazz, "proxy/lambda classes with interfaces initialized at build time are also initialized at build time", false);
162+
if (superResult == InitKind.BUILD_TIME && Proxy.isProxyClass(clazz)) {
163+
forceInitializeHosted(clazz, "proxy classes with interfaces initialized at build time are also initialized at build time", false);
166164
return InitKind.BUILD_TIME;
167165
}
168166

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
import org.graalvm.collections.Pair;
4141
import org.graalvm.compiler.graph.Node;
42+
import org.graalvm.compiler.java.LambdaUtils;
4243
import org.graalvm.compiler.options.OptionValues;
4344
import org.graalvm.compiler.phases.util.Providers;
4445
import org.graalvm.nativeimage.impl.clinit.ClassInitializationTracking;
@@ -204,6 +205,7 @@ public void afterAnalysis(AfterAnalysisAccess a) {
204205
.filter(c -> c.getClassLoader() != null && c.getClassLoader() != ClassLoader.getPlatformClassLoader())
205206
.filter(c -> classInitializationSupport.specifiedInitKindFor(c) == null)
206207
.map(Class::getTypeName)
208+
.filter(name -> !LambdaUtils.isLambdaName(name))
207209
.collect(Collectors.toList());
208210
if (!unspecifiedClasses.isEmpty()) {
209211
System.err.println("The following classes have unspecified initialization policy:" + System.lineSeparator() + String.join(System.lineSeparator(), unspecifiedClasses));

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ private static class InitializationValueEager extends InitializationValueTransfo
100100
@Option(help = "Assert class initialization is specified for all classes.", type = OptionType.Debug)//
101101
public static final HostedOptionKey<Boolean> AssertInitializationSpecifiedForAllClasses = new HostedOptionKey<>(false);
102102

103-
@Option(help = "Use new class initialization strategy that allows all classes to be used at image build time.", type = OptionType.Expert)//
104-
public static final HostedOptionKey<Boolean> UseNewExperimentalClassInitialization = new HostedOptionKey<>(false);
103+
@Option(help = "Use the old class initialization strategy that does not allow all classes to be used at image build time.", type = OptionType.Expert, //
104+
deprecated = true, deprecationMessage = "Temporary flag to restore the class initialization behavior of older GraalVM versions. The old class initialization strategy will be removed in a future version of GraalVM.") //
105+
public static final HostedOptionKey<Boolean> UseDeprecatedOldClassInitialization = new HostedOptionKey<>(false);
105106

106107
@Option(help = "Simulate the effects of class initializer at image build time, to avoid class initialization at run time.", type = OptionType.Expert)//
107108
public static final HostedOptionKey<Boolean> SimulateClassInitializer = new HostedOptionKey<>(true);

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ public abstract class ClassInitializationSupport implements RuntimeClassInitiali
8585
final MetaAccessProvider metaAccess;
8686

8787
public static ClassInitializationSupport create(MetaAccessProvider metaAccess, ImageClassLoader loader) {
88-
if (ClassInitializationOptions.UseNewExperimentalClassInitialization.getValue()) {
89-
LogUtils.warning("Using new experimental class initialization strategy. Image size and peak performance are not optimized yet!");
90-
return new AllowAllHostedUsagesClassInitializationSupport(metaAccess, loader);
88+
if (ClassInitializationOptions.UseDeprecatedOldClassInitialization.getValue()) {
89+
LogUtils.warning("Using old deprecated class initialization strategy. Only classes that are marked explicitly as '--initialize-at-build-time' can be used during image generation.");
90+
return new ProvenSafeClassInitializationSupport(metaAccess, loader);
9191
}
92-
return new ProvenSafeClassInitializationSupport(metaAccess, loader);
92+
return new AllowAllHostedUsagesClassInitializationSupport(metaAccess, loader);
9393
}
9494

9595
public static ClassInitializationSupport singleton() {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,18 @@ private void checkDisallowedMBeanObjects(Object original) {
168168
}
169169

170170
private RuntimeException error(String msg, Object obj, String initializerAction) {
171+
String suffix = "";
172+
if (!ClassInitializationOptions.UseDeprecatedOldClassInitialization.getValue()) {
173+
suffix = System.lineSeparator() +
174+
"If you see this error while migrating to a newer GraalVM release, please note that the class initialization strategy has changed in GraalVM for JDK 21." +
175+
" All classes can now be used at image build time. However, only classes explicitly marked as --initialize-at-built-time are allowed to be in the image heap." +
176+
" This rule is now strictly enforced, i.e., the problem might be solvable by registering the reported type as --initialize-at-built-time.";
177+
}
171178
throw new UnsupportedFeatureException(msg + " " + classInitialization.objectInstantiationTraceMessage(obj, initializerAction) + " " +
172179
"The object was probably created by a class initializer and is reachable from a static field. " +
173180
"You can request class initialization at image runtime by using the option " +
174181
SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, "<class-name>", "initialize-at-run-time") + ". " +
175-
"Or you can write your own initialization methods and call them explicitly from your main entry point.");
182+
"Or you can write your own initialization methods and call them explicitly from your main entry point." + suffix);
176183
}
177184

178185
private static boolean search(byte[] haystack, byte[] needle) {

substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitialization.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,8 @@ public void afterImageWrite(AfterImageWriteAccess access) {
714714
}
715715

716716
/**
717-
* For testing with {@link ClassInitializationOptions#UseNewExperimentalClassInitialization} set to
718-
* false and simulation of class initializer disabled.
717+
* For testing with {@link ClassInitializationOptions#UseDeprecatedOldClassInitialization} set to
718+
* true and simulation of class initializer disabled.
719719
*/
720720
class TestClassInitializationFeatureOldPolicyFeature extends TestClassInitializationFeature {
721721

@@ -752,8 +752,8 @@ void checkClass(Class<?> checkedClass, boolean checkSafeEarly, boolean checkSafe
752752
}
753753

754754
/**
755-
* For testing with {@link ClassInitializationOptions#UseNewExperimentalClassInitialization} set to
756-
* true and simulation of class initializer enabled.
755+
* For testing with {@link ClassInitializationOptions#UseDeprecatedOldClassInitialization} set to
756+
* false and simulation of class initializer enabled.
757757
*/
758758
class TestClassInitializationFeatureNewPolicyFeature extends TestClassInitializationFeature {
759759
@Override

0 commit comments

Comments
 (0)