Skip to content

Commit

Permalink
Flip the class initialization flag
Browse files Browse the repository at this point in the history
  • Loading branch information
vjovanov committed Sep 12, 2023
1 parent 9907449 commit b8fd7c4
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 21 deletions.
9 changes: 9 additions & 0 deletions docs/reference-manual/native-image/BuildOutput.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,15 @@ This feature is currently only available for Linux AArch64 and leverages pointer
The build output may contain one or more of the following recommendations that help you get the best out of Native Image.
#### <a name="recommendation-init"></a>`INIT`: Use the Strict Image Heap Configuration
Start using `--strict-image-heap` to reduce the amount of configuration and prepare for future GraalVM releases where this will be the default.
This mode requires only the classes that are stored in the image heap to be marked with `--initialize-at-build-time`.
This effectively reduces the number of configuration entries necessary to achieve build-time initialization.
When adopting the new mode it is best to start introducing build-time initialization from scratch.
During this process, it is best to select individual classes (as opposed to whole packages) for build time initialization.
Also, before migrating to the new flag make sure to update all framework dependencies to the latest versions as they might need to migrate too.
#### <a name="recommendation-awt"></a>`AWT`: Missing Reachability Metadata for Abstract Window Toolkit
The Native Image analysis has included classes from the [`java.awt` package](https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/package-summary.html) but could not find any reachability metadata for it.
Expand Down
2 changes: 1 addition & 1 deletion substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,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-39406) New option `--strict-image-heap`: 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. Adopt this option as it will become the default in the next release of GraalVM.
* (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.
* (GR-38994) Together with Red Hat, we added support for `-XX:+HeapDumpOnOutOfMemoryError`.
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 @@ -1514,9 +1514,9 @@ def build_and_test_clinittest_image(native_image, args, new_class_init_policy):
mx.ensure_dir_exists(build_dir)

if new_class_init_policy:
policy_args = svm_experimental_options(['-H:-UseDeprecatedOldClassInitialization', '-H:+SimulateClassInitializer']) + ['--features=com.oracle.svm.test.clinit.TestClassInitializationFeatureNewPolicyFeature']
policy_args = svm_experimental_options(['-H:+StrictImageHeap', '-H:+SimulateClassInitializer']) + ['--features=com.oracle.svm.test.clinit.TestClassInitializationFeatureNewPolicyFeature']
else:
policy_args = svm_experimental_options(['-H:+UseDeprecatedOldClassInitialization', '-H:-SimulateClassInitializer']) + ['--features=com.oracle.svm.test.clinit.TestClassInitializationFeatureOldPolicyFeature']
policy_args = svm_experimental_options(['-H:-SimulateClassInitializer']) + ['--features=com.oracle.svm.test.clinit.TestClassInitializationFeatureOldPolicyFeature']

# Build and run the example
binary_path = join(build_dir, 'clinittest')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import java.util.List;
import java.util.function.Supplier;

import com.oracle.svm.util.LogUtils;
import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.BuildArtifacts;
Expand All @@ -38,12 +37,15 @@
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.jni.access.JNIAccessibleClass;
import com.oracle.svm.core.jni.access.JNIReflectionDictionary;
import com.oracle.svm.core.option.SubstrateOptionsParser;
import com.oracle.svm.hosted.FeatureImpl.AfterCompilationAccessImpl;
import com.oracle.svm.hosted.FeatureImpl.BeforeImageWriteAccessImpl;
import com.oracle.svm.hosted.ProgressReporter.DirectPrinter;
import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions;
import com.oracle.svm.hosted.jdk.JNIRegistrationSupport;
import com.oracle.svm.hosted.util.CPUTypeAArch64;
import com.oracle.svm.hosted.util.CPUTypeAMD64;
import com.oracle.svm.util.LogUtils;

@AutomaticallyRegisteredFeature
public class ProgressReporterFeature implements InternalFeature {
Expand Down Expand Up @@ -90,6 +92,10 @@ public void createAdditionalArtifacts(@SuppressWarnings("unused") BuildArtifacts

protected List<UserRecommendation> getRecommendations() {
return List.of(// in order of appearance:
new UserRecommendation("INIT",
"Adopt " + SubstrateOptionsParser.commandArgument(ClassInitializationOptions.StrictImageHeap, "+", "strict-initial-heap", true, false) +
" to prepare for the next GraalVM release.",
() -> !ClassInitializationOptions.StrictImageHeap.getValue()),
new UserRecommendation("AWT", "Use the tracing agent to collect metadata for AWT.", ProgressReporterFeature::recommendTraceAgentForAWT),
new UserRecommendation("HEAP", "Set max heap for improved and more predictable memory usage.", () -> SubstrateGCOptions.MaxHeapSize.getValue() == 0),
new UserRecommendation("CPU", "Enable more CPU features with '-march=native' for improved performance.", ProgressReporterFeature::recommendMArchNative));
Expand Down Expand Up @@ -126,7 +132,8 @@ private static boolean recommendTraceAgentForAWT() {
public record UserRecommendation(String id, String description, Supplier<Boolean> isApplicable) {
public UserRecommendation(String id, String description, Supplier<Boolean> isApplicable) {
assert id.toUpperCase().equals(id) && id.length() < 5 : "id must be uppercase and have fewer than 5 chars";
assert description.length() < 74 : "description must have fewer than 74 chars to fit in terminal";
int max_length = 74;
assert description.length() < max_length : "description must have fewer than " + max_length + " chars to fit in terminal. Length: " + description.length();
this.id = id;
this.description = description;
this.isApplicable = isApplicable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,16 @@ private Object checkImageHeapInstance(Object obj) {
}
});

if (!ClassInitializationOptions.UseDeprecatedOldClassInitialization.getValue()) {
if (ClassInitializationOptions.StrictImageHeap.getValue()) {
msg += """
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-build-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-build-time.
""".replaceAll("\n", System.lineSeparator());
If you are seeing this message after enabling %s, this means that some objects ended up in the image heap without their type being marked with --initialize-at-build-time.
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.
Please address this problem to be prepared for future releases of GraalVM.
"""
.replaceAll("\n", System.lineSeparator())
.formatted(
SubstrateOptionsParser.commandArgument(ClassInitializationOptions.StrictImageHeap, typeName, "strict-image-heap", true, false),
SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, typeName, "initialize-at-build-time", true, false));
}

msg += System.lineSeparator() + "The following detailed trace displays from which field in the code the object was reached.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.oracle.svm.core.option.APIOption;
import com.oracle.svm.core.option.HostedOptionKey;
import com.oracle.svm.core.option.LocatableMultiOptionValue;
import com.oracle.svm.core.util.UserError;

public final class ClassInitializationOptions {

Expand Down Expand Up @@ -100,9 +101,13 @@ 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 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);
@APIOption(name = "strict-image-heap")//
@Option(help = "Enable the strict image heap mode that allows all classes to be used at build-time but also requires types of all objects in the heap to be explicitly marked for build-time initialization.", type = OptionType.User) //
public static final HostedOptionKey<Boolean> StrictImageHeap = new HostedOptionKey<>(false, k -> {
if (k.hasBeenSet() && Boolean.FALSE.equals(k.getValue())) {
throw UserError.abort("Strict image heap mode cannot be explicitly disabled.");
}
});

@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 @@ -52,7 +52,6 @@
import com.oracle.svm.core.util.UserError;
import com.oracle.svm.hosted.ImageClassLoader;
import com.oracle.svm.hosted.LinkAtBuildTimeSupport;
import com.oracle.svm.util.LogUtils;

import jdk.internal.misc.Unsafe;
import jdk.vm.ci.meta.MetaAccessProvider;
Expand Down Expand Up @@ -89,8 +88,7 @@ public abstract class ClassInitializationSupport implements RuntimeClassInitiali
final MetaAccessProvider metaAccess;

public static ClassInitializationSupport create(MetaAccessProvider metaAccess, ImageClassLoader 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.");
if (!ClassInitializationOptions.StrictImageHeap.getValue()) {
return new ProvenSafeClassInitializationSupport(metaAccess, loader);
}
return new AllowAllHostedUsagesClassInitializationSupport(metaAccess, loader);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -727,8 +727,8 @@ public void afterImageWrite(AfterImageWriteAccess access) {
}

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

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

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

0 comments on commit b8fd7c4

Please sign in to comment.