Skip to content

Commit

Permalink
[GR-39406] Allow all classes to be used at image build time.
Browse files Browse the repository at this point in the history
PullRequest: graal/12091
  • Loading branch information
Christian Wimmer committed Jul 18, 2023
2 parents c6e1f85 + f3114f9 commit c38d527
Show file tree
Hide file tree
Showing 8 changed files with 26 additions and 17 deletions.
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.

This comment has been minimized.

Copy link
@maxandersen

maxandersen Jul 18, 2023

commit says graal/12091 PR I can't find that - got a better link?

This comment has been minimized.

Copy link
@fniephaus

fniephaus Jul 18, 2023

Member

How about #4684?

* (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 @@ -204,6 +205,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 @@ -85,11 +85,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

0 comments on commit c38d527

Please sign in to comment.