Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable new class initialization strategy by default #6544

Merged
merged 2 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This changelog summarizes major changes to GraalVM Native Image.
* (GR-45841) BellSoft added support for the JFR event ThreadCPULoad.
* (GR-45994) Removed the option `-H:EnableSignalAPI`. Please use the runtime option `EnableSignalHandling` if it is necessary to enable or disable signal handling explicitly.
* (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.
* (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.
* (GR-46392) Add `--parallelism` option to control how many threads are used by the build process.
* (GR-46392) Add build resources section to the build output that shows the memory and thread limits of the build process.

Expand Down
4 changes: 2 additions & 2 deletions substratevm/mx.substratevm/mx_substratevm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1413,9 +1413,9 @@ def build_and_test_clinittest_image(native_image, args, new_class_init_policy):
mkpath(build_dir)

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

# Build and run the example
native_image(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@

import java.lang.reflect.Proxy;

import org.graalvm.compiler.java.LambdaUtils;

import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
import com.oracle.svm.core.util.UserError;
Expand Down Expand Up @@ -161,8 +159,8 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize)
}
superResult = superResult.max(processInterfaces(clazz, memoize));

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

import org.graalvm.collections.Pair;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.java.LambdaUtils;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.nativeimage.impl.clinit.ClassInitializationTracking;
Expand Down Expand Up @@ -207,6 +208,7 @@ public void afterAnalysis(AfterAnalysisAccess a) {
.filter(c -> c.getClassLoader() != null && c.getClassLoader() != ClassLoader.getPlatformClassLoader())
.filter(c -> classInitializationSupport.specifiedInitKindFor(c) == null)
.map(Class::getTypeName)
.filter(name -> !LambdaUtils.isLambdaName(name))
.collect(Collectors.toList());
if (!unspecifiedClasses.isEmpty()) {
System.err.println("The following classes have unspecified initialization policy:" + System.lineSeparator() + String.join(System.lineSeparator(), unspecifiedClasses));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,9 @@ private static class InitializationValueEager extends InitializationValueTransfo
@Option(help = "Assert class initialization is specified for all classes.", type = OptionType.Debug)//
public static final HostedOptionKey<Boolean> AssertInitializationSpecifiedForAllClasses = new HostedOptionKey<>(false);

@Option(help = "Use new class initialization strategy that allows all classes to be used at image build time.", type = OptionType.Expert)//
public static final HostedOptionKey<Boolean> UseNewExperimentalClassInitialization = new HostedOptionKey<>(false);
@Option(help = "Use the old class initialization strategy that does not allow all classes to be used at image build time.", type = OptionType.Expert, //
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.") //
public static final HostedOptionKey<Boolean> UseDeprecatedOldClassInitialization = new HostedOptionKey<>(false);

@Option(help = "Simulate the effects of class initializer at image build time, to avoid class initialization at run time.", type = OptionType.Expert)//
public static final HostedOptionKey<Boolean> SimulateClassInitializer = new HostedOptionKey<>(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ public abstract class ClassInitializationSupport implements RuntimeClassInitiali
final MetaAccessProvider metaAccess;

public static ClassInitializationSupport create(MetaAccessProvider metaAccess, ImageClassLoader loader) {
if (ClassInitializationOptions.UseNewExperimentalClassInitialization.getValue()) {
LogUtils.warning("Using new experimental class initialization strategy. Image size and peak performance are not optimized yet!");
return new AllowAllHostedUsagesClassInitializationSupport(metaAccess, loader);
if (ClassInitializationOptions.UseDeprecatedOldClassInitialization.getValue()) {
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.");
return new ProvenSafeClassInitializationSupport(metaAccess, loader);
}
return new ProvenSafeClassInitializationSupport(metaAccess, loader);
return new AllowAllHostedUsagesClassInitializationSupport(metaAccess, loader);
}

public static ClassInitializationSupport singleton() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,18 @@ private void checkDisallowedMBeanObjects(Object original) {
}

private RuntimeException error(String msg, Object obj, String initializerAction) {
String suffix = "";
if (!ClassInitializationOptions.UseDeprecatedOldClassInitialization.getValue()) {
suffix = System.lineSeparator() +
"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." +
" 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." +
" This rule is now strictly enforced, i.e., the problem might be solvable by registering the reported type as --initialize-at-built-time.";
}
throw new UnsupportedFeatureException(msg + " " + classInitialization.objectInstantiationTraceMessage(obj, initializerAction) + " " +
"The object was probably created by a class initializer and is reachable from a static field. " +
"You can request class initialization at image runtime by using the option " +
SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, "<class-name>", "initialize-at-run-time") + ". " +
"Or you can write your own initialization methods and call them explicitly from your main entry point.");
"Or you can write your own initialization methods and call them explicitly from your main entry point." + suffix);
}

private static boolean search(byte[] haystack, byte[] needle) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -714,8 +714,8 @@ public void afterImageWrite(AfterImageWriteAccess access) {
}

/**
* For testing with {@link ClassInitializationOptions#UseNewExperimentalClassInitialization} set to
* false and simulation of class initializer disabled.
* For testing with {@link ClassInitializationOptions#UseDeprecatedOldClassInitialization} set to
* true and simulation of class initializer disabled.
*/
class TestClassInitializationFeatureOldPolicyFeature extends TestClassInitializationFeature {

Expand Down Expand Up @@ -752,8 +752,8 @@ void checkClass(Class<?> checkedClass, boolean checkSafeEarly, boolean checkSafe
}

/**
* For testing with {@link ClassInitializationOptions#UseNewExperimentalClassInitialization} set to
* true and simulation of class initializer enabled.
* For testing with {@link ClassInitializationOptions#UseDeprecatedOldClassInitialization} set to
* false and simulation of class initializer enabled.
*/
class TestClassInitializationFeatureNewPolicyFeature extends TestClassInitializationFeature {
@Override
Expand Down