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

[GR-50683] Initialize most of java.xml at run time. #10537

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -67,4 +67,11 @@ default void rerunInitialization(Class<?> aClass, String reason) {
}

void initializeAtBuildTime(Class<?> aClass, String reason);

/**
* Returns if the <code>className</code> was marked for build-time initialization. The result
* applies both if a package prefix or a fully-qualified class name were configured as build
* time.
*/
boolean isMarkedForBuildTimeInitialization(String className);
}
3 changes: 2 additions & 1 deletion substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ This changelog summarizes major changes to GraalVM Native Image.

## GraalVM for JDK 25
* (GR-58668) Enabled [Whole-Program Sparse Conditional Constant Propagation (WP-SCCP)](https://github.com/oracle/graal/pull/9821) by default, improving the precision of points-to analysis in Native Image. This optimization enhances static analysis accuracy and scalability, potentially reducing the size of the final native binary.
* (GR-59313) Deprecated class-level metadata extraction using `native-image-inspect` and removed option `DumpMethodsData`. Use class-level SBOMs instead by passing `--enable-sbom=class-level,export` to the `native-image` builder. The default value of option `IncludeMethodData` was changed to `false`.
* (GR-59313) Deprecated class-level metadata extraction using `native-image-inspect` and removed option `DumpMethodsData`. Use class-level SBOMs instead by passing `--enable-sbom=class-level,export` to the `native-image` builder. The default value of option `IncludeMethodData` was changed to `false`.
* (GR-52400) The build process now uses 85% of system memory in containers and CI environments. Otherwise, it tries to only use available memory. If less than 8GB of memory are available, it falls back to 85% of system memory. The reason for the selected memory limit is now also shown in the build resources section of the build output.
* (GR-59864) Added JVM version check to the Native Image agent. The agent will abort execution if the JVM major version does not match the version it was built with, and warn if the full JVM version is different.
* (GR-59135) Verify if hosted options passed to `native-image` exist prior to starting the builder. Provide suggestions how to fix unknown options early on.
* (GR-49525) Introduced build-time `-H:+InitializeJDKAtBuildTimeMigration` that reverts parts of the JDK initialization to pre GraalVM 25 state. This flag should be used only to quickly fix projects that fail until the correct class-initialization configuration is introduced for the project.

## GraalVM for JDK 24 (Internal Version 24.2.0)
* (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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,10 @@ public Boolean getValueOrDefault(UnmodifiableEconomicMap<OptionKey<?>, Object> v
deprecated = true, deprecationMessage = "This option was introduced to simplify migration to GraalVM 23.0 and will be removed in a future release")//
public static final HostedOptionKey<Boolean> AllowDeprecatedBuilderClassesOnImageClasspath = new HostedOptionKey<>(false);

@Option(help = "Initialize JDK classes at build time the same way it was done before GraalVM 25.", type = OptionType.Debug, //
deprecated = true, deprecationMessage = "This option was introduced to simplify migration to GraalVM 25 and will be removed in a future release")//
public static final HostedOptionKey<Boolean> InitializeJDKAtBuildTimeMigration = new HostedOptionKey<>(false);

@APIOption(name = "exact-reachability-metadata", defaultValue = "")//
@Option(help = "file:doc-files/ExactReachabilityMetadataHelp.txt")//
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> ThrowMissingRegistrationErrors = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.jdk;

import java.util.function.Predicate;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;

public class MarkedAsBuildTimeInitialized implements Predicate<String> {
@Override
public boolean test(String className) {
return ImageSingletons.lookup(RuntimeClassInitializationSupport.class).isMarkedForBuildTimeInitialization(className);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.jdk.xml;

import java.util.function.Predicate;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;

public class MarkedAsBuildTimeInitialized implements Predicate<String> {
@Override
public boolean test(String className) {
return ImageSingletons.lookup(RuntimeClassInitializationSupport.class).isMarkedForBuildTimeInitialization(className);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.jdk.JDKLatest;
import com.oracle.svm.core.jdk.MarkedAsBuildTimeInitialized;
import com.oracle.svm.util.ReflectionUtil;

/**
Expand All @@ -46,7 +47,7 @@
* Ideally, we would initialize all of {@code jdk.xml} at run time, but that is too intrusive at the
* current point in time (GR-50683).
*/
@TargetClass(className = "jdk.xml.internal.JdkCatalog", onlyWith = JDKLatest.class)
@TargetClass(className = "jdk.xml.internal.JdkCatalog", onlyWith = {JDKLatest.class, MarkedAsBuildTimeInitialized.class})
public final class Target_jdk_xml_internal_JdkCatalog {
@Alias //
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = JdkCatalogSupplier.class, isFinal = true) //
Expand All @@ -63,7 +64,7 @@ public static void init(String resolve) {
final class Target_javax_xml_catalog_Catalog {
}

@TargetClass(className = "javax.xml.catalog.CatalogImpl")
@TargetClass(className = "javax.xml.catalog.CatalogImpl", onlyWith = MarkedAsBuildTimeInitialized.class)
final class Target_javax_xml_catalog_CatalogImpl {
@Alias //
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,12 @@ private void checkImageHeapInstance(DuringAnalysisAccess access, Object obj, Obj
msg += """
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.
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.
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.
"""
.replaceAll("\n", System.lineSeparator())
.formatted(SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, proxyOrLambda ? proxyLambdaInterfaceCSV : typeName,
"initialize-at-build-time", true, false));
"initialize-at-build-time", true, false),
SubstrateOptionsParser.commandArgument(SubstrateOptions.InitializeJDKAtBuildTimeMigration, "+"));

msg += System.lineSeparator() + "The following detailed trace displays from which field in the code the object was reached.";
throw new UnsupportedFeatureException(msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ public void initializeAtBuildTime(String name, String reason) {
}
}

@Override
public boolean isMarkedForBuildTimeInitialization(String className) {
return InitKind.BUILD_TIME == classInitializationConfiguration.lookupKind(className).getLeft();
}

static boolean isClassListedInStringOption(AccumulatingLocatableMultiOptionValue.Strings option, Class<?> clazz) {
return option.values().contains(clazz.getName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

@AutomaticallyRegisteredFeature
public class JDKInitializationFeature implements InternalFeature {
private static final String JDK_CLASS_REASON = "Core JDK classes are initialized at build time";
static final String JDK_CLASS_REASON = "Core JDK classes are initialized at build time";

@Override
public void afterRegistration(AfterRegistrationAccess access) {
Expand All @@ -71,8 +71,10 @@ public void afterRegistration(AfterRegistrationAccess access) {
rci.initializeAtBuildTime("java.net", JDK_CLASS_REASON);
rci.initializeAtBuildTime("java.nio", JDK_CLASS_REASON);
rci.initializeAtBuildTime("java.text", JDK_CLASS_REASON);

rci.initializeAtBuildTime("java.time", JDK_CLASS_REASON);
rci.initializeAtRunTime("java.time.chrono.HijrahChronology", "Reads java.home in class initializer.");

rci.initializeAtBuildTime("java.util", JDK_CLASS_REASON);
rci.initializeAtRunTime("java.util.concurrent.SubmissionPublisher", "Executor service must be recomputed");

Expand All @@ -82,22 +84,12 @@ public void afterRegistration(AfterRegistrationAccess access) {
rci.initializeAtBuildTime("javax.naming", JDK_CLASS_REASON);
rci.initializeAtBuildTime("javax.net", JDK_CLASS_REASON);
rci.initializeAtBuildTime("javax.tools", JDK_CLASS_REASON);
rci.initializeAtBuildTime("javax.xml", JDK_CLASS_REASON);

rci.initializeAtBuildTime("jdk.internal", JDK_CLASS_REASON);
rci.initializeAtBuildTime("jdk.jfr", "Needed for Native Image substitutions");
rci.initializeAtBuildTime("jdk.net", JDK_CLASS_REASON);
rci.initializeAtBuildTime("jdk.nio", JDK_CLASS_REASON);
rci.initializeAtBuildTime("jdk.vm.ci", "Native Image classes are always initialized at build time");
rci.initializeAtBuildTime("jdk.xml", JDK_CLASS_REASON);
/*
* The XML classes have cyclic class initializer dependencies, and class initialization can
* deadlock/fail when initialization is started at the "wrong part" of the cycle.
* Force-initializing the correct class of the cycle here, in addition to the
* "whole package" initialization above, breaks the cycle because it triggers immediate
* initilalization here before the static analysis is started.
*/
rci.initializeAtBuildTime("jdk.xml.internal.JdkXmlUtils", JDK_CLASS_REASON);

rci.initializeAtBuildTime("sun.invoke", JDK_CLASS_REASON);
rci.initializeAtBuildTime("sun.launcher", JDK_CLASS_REASON);
Expand Down Expand Up @@ -138,11 +130,6 @@ public void afterRegistration(AfterRegistrationAccess access) {
rci.initializeAtBuildTime("java.awt.font.NumericShaper", "Required for sun.text.bidi.BidiBase.NumericShapings");
rci.initializeAtBuildTime("java.awt.font.JavaAWTFontAccessImpl", "Required for sun.text.bidi.BidiBase.NumericShapings");

/* XML-related */
rci.initializeAtBuildTime("com.sun.xml", JDK_CLASS_REASON);
rci.initializeAtBuildTime("com.sun.org.apache", JDK_CLASS_REASON);
rci.initializeAtBuildTime("com.sun.org.slf4j.internal", JDK_CLASS_REASON);

/* Security services */
rci.initializeAtBuildTime("com.sun.crypto.provider", JDK_CLASS_REASON);
rci.initializeAtBuildTime("com.sun.security.auth", JDK_CLASS_REASON);
Expand All @@ -152,6 +139,16 @@ public void afterRegistration(AfterRegistrationAccess access) {
rci.initializeAtBuildTime("com.sun.security.sasl", JDK_CLASS_REASON);

rci.initializeAtBuildTime("java.security", JDK_CLASS_REASON);
rci.initializeAtBuildTime("javax.xml.catalog.CatalogImpl", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");
rci.initializeAtBuildTime("javax.xml.catalog.CatalogResolver$NotFoundAction$1", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");
rci.initializeAtBuildTime("javax.xml.catalog.CatalogResolver$NotFoundAction$2", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");
rci.initializeAtBuildTime("javax.xml.catalog.CatalogResolver$NotFoundAction$3", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");
rci.initializeAtBuildTime("javax.xml.catalog.SystemSuffix", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");
rci.initializeAtBuildTime("javax.xml.catalog.SystemEntry", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");
rci.initializeAtBuildTime("javax.xml.catalog.CatalogFeatures", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");
rci.initializeAtBuildTime("javax.xml.catalog.BaseEntry$CatalogEntryType", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");
rci.initializeAtBuildTime("javax.xml.catalog.CatalogFeatures$State", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");
rci.initializeAtBuildTime("javax.xml.catalog.PublicEntry", "Security providers initialized at build time: jdk.xml.internal.XMLSecurityManager");

rci.initializeAtBuildTime("javax.crypto", JDK_CLASS_REASON);
rci.initializeAtBuildTime("javax.security.auth", JDK_CLASS_REASON);
Expand Down Expand Up @@ -216,8 +213,6 @@ public void afterRegistration(AfterRegistrationAccess access) {
rci.initializeAtRunTime("jdk.internal.foreign.abi.fallback.FFIABI", "Fails build-time initialization");
rci.initializeAtRunTime("sun.reflect.misc.Trampoline", "Fails build-time initialization");

rci.initializeAtRunTime("com.sun.org.apache.xml.internal.serialize.HTMLdtd", "Fails build-time initialization");

rci.initializeAtRunTime("sun.security.ssl.SSLContextImpl$DefaultSSLContextHolder", "Stores secure random");
rci.initializeAtRunTime("sun.security.ssl.SSLSocketFactoryImpl", "Stores secure random");
rci.initializeAtRunTime("sun.security.provider.certpath.ssl.SSLServerCertStore", "Stores secure random");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.hosted.jdk;

import static com.oracle.svm.core.SubstrateOptions.InitializeJDKAtBuildTimeMigration;
import static com.oracle.svm.hosted.jdk.JDKInitializationFeature.JDK_CLASS_REASON;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;

import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;

@AutomaticallyRegisteredFeature
public class JDKInitializationMigrationFeature implements InternalFeature {

@Override
public void afterRegistration(AfterRegistrationAccess access) {
RuntimeClassInitializationSupport rci = ImageSingletons.lookup(RuntimeClassInitializationSupport.class);
if (InitializeJDKAtBuildTimeMigration.getValue()) {
/* Place all excluded entries from JDKInitializationFeature here. */
rci.initializeAtBuildTime("jdk.xml", JDK_CLASS_REASON);
/*
* The XML classes have cyclic class initializer dependencies, and class initialization
* can deadlock/fail when initialization is started at the "wrong part" of the cycle.
* Force-initializing the correct class of the cycle here, in addition to the
* "whole package" initialization above, breaks the cycle because it triggers immediate
* initialization here before the static analysis is started.
*/
rci.initializeAtBuildTime("jdk.xml.internal.JdkXmlUtils", JDK_CLASS_REASON);
/* XML-related */
rci.initializeAtBuildTime("com.sun.xml", JDK_CLASS_REASON);
rci.initializeAtBuildTime("com.sun.org.apache", JDK_CLASS_REASON);
rci.initializeAtRunTime("com.sun.org.apache.xml.internal.serialize.HTMLdtd", "Fails build-time initialization");
rci.initializeAtBuildTime("com.sun.org.slf4j.internal", JDK_CLASS_REASON);
}
}
}
Loading
Loading