From 4217cdb768d0cc44f183536bdfb4cfceeea9713a Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Thu, 15 Feb 2024 15:07:23 +0200 Subject: [PATCH 1/3] Switch to runtime initialization instead of rerun They both have the same result starting with 23.1. Runtime initialization is public API while rerun is not, and will soon be deprecated and at some point removed in future releases. See https://github.com/oracle/graal/issues/5013#issuecomment-1944747803 and https://github.com/oracle/graal/pull/8323/ --- .../steps/NativeImageFeatureStep.java | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java index f91930e898ed8..7f9217f093ba2 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java @@ -20,6 +20,7 @@ import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.UnsafeAccessedFieldBuildItem; import io.quarkus.deployment.pkg.NativeConfig; +import io.quarkus.gizmo.AssignableResultHandle; import io.quarkus.gizmo.BranchResult; import io.quarkus.gizmo.BytecodeCreator; import io.quarkus.gizmo.CatchBlockCreator; @@ -176,29 +177,50 @@ public void write(String s, byte[] bytes) { // hack in reinitialization of process info classes if (!runtimeReinitializedClassBuildItems.isEmpty()) { MethodCreator runtimeReinitializedClasses = file - .getMethodCreator("runtimeReinitializedClasses", void.class) + .getMethodCreator("runtimeReinitializedClasses", Class[].class) .setModifiers(Modifier.PRIVATE | Modifier.STATIC); ResultHandle thisClass = runtimeReinitializedClasses.loadClassFromTCCL(GRAAL_FEATURE); ResultHandle cl = runtimeReinitializedClasses.invokeVirtualMethod( ofMethod(Class.class, "getClassLoader", ClassLoader.class), thisClass); - ResultHandle quarkus = runtimeReinitializedClasses.load("Quarkus"); - ResultHandle imageSingleton = runtimeReinitializedClasses.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP, - runtimeReinitializedClasses.loadClassFromTCCL(RUNTIME_CLASS_INITIALIZATION_SUPPORT)); - for (RuntimeReinitializedClassBuildItem runtimeReinitializedClass : runtimeReinitializedClassBuildItems) { + ResultHandle classesArray = runtimeReinitializedClasses.newArray(Class.class, + runtimeReinitializedClasses.load(runtimeReinitializedClassBuildItems.size())); + for (int i = 0; i < runtimeReinitializedClassBuildItems.size(); i++) { TryBlock tc = runtimeReinitializedClasses.tryBlock(); ResultHandle clazz = tc.invokeStaticMethod( ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class), - tc.load(runtimeReinitializedClass.getClassName()), tc.load(false), cl); - tc.invokeInterfaceMethod(RERUN_INITIALIZATION, imageSingleton, clazz, quarkus); - + tc.load(runtimeReinitializedClassBuildItems.get(i).getClassName()), tc.load(false), cl); + tc.writeArrayValue(classesArray, i, clazz); CatchBlockCreator cc = tc.addCatch(Throwable.class); cc.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), cc.getCaughtException()); } - runtimeReinitializedClasses.returnVoid(); + runtimeReinitializedClasses.returnValue(classesArray); - overallCatch.invokeStaticMethod(runtimeReinitializedClasses.getMethodDescriptor()); + ResultHandle classes = overallCatch.invokeStaticMethod(runtimeReinitializedClasses.getMethodDescriptor()); + + ResultHandle graalVMVersion = overallCatch.invokeStaticMethod(GRAALVM_VERSION_GET_CURRENT); + BranchResult graalVm23_1Test = overallCatch + .ifGreaterEqualZero(overallCatch.invokeVirtualMethod(GRAALVM_VERSION_COMPARE_TO, graalVMVersion, + overallCatch.marshalAsArray(int.class, overallCatch.load(23), overallCatch.load(1)))); + /* GraalVM >= 23.1 */ + try (BytecodeCreator greaterEqual23_1 = graalVm23_1Test.trueBranch()) { + greaterEqual23_1.invokeStaticMethod(INITIALIZE_CLASSES_AT_RUN_TIME, classes); + } + /* GraalVM < 23.1 */ + try (BytecodeCreator less23_1 = graalVm23_1Test.falseBranch()) { + ResultHandle quarkus = less23_1.load("Quarkus"); + ResultHandle imageSingleton = less23_1.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP, + less23_1.loadClassFromTCCL(RUNTIME_CLASS_INITIALIZATION_SUPPORT)); + ResultHandle arraySize = less23_1.arrayLength(classes); + AssignableResultHandle index = less23_1.createVariable(int.class); + less23_1.assign(index, less23_1.load(0)); + try (BytecodeCreator loop = less23_1.whileLoop(c -> c.ifIntegerLessThan(index, arraySize)).block()) { + loop.invokeInterfaceMethod(RERUN_INITIALIZATION, imageSingleton, loop.readArrayValue(classes, index), + quarkus); + loop.assign(index, loop.increment(index)); + } + } } // Ensure registration of fields being accessed through unsafe is done last to ensure that the class From ec2b9badb15bec45d54716e22b596098898a734e Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Wed, 15 Jan 2025 15:27:50 +0200 Subject: [PATCH 2/3] Runtime reinitialize NioSocketImpl for backward compatibility This change does not have any impact in Mandrel/GraalVM for JDK 21 and later versions, but allows Quarkus to build with Mandrel/GraalVM for JDK 17. --- .../java/io/quarkus/deployment/NioSocketImplProcessor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/NioSocketImplProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/NioSocketImplProcessor.java index 9f8d7098bcf7b..a5aaa4beda55e 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/NioSocketImplProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/NioSocketImplProcessor.java @@ -1,14 +1,14 @@ package io.quarkus.deployment; import io.quarkus.deployment.annotations.BuildStep; -import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem; +import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem; public class NioSocketImplProcessor { // Workaround till https://github.com/oracle/graal/pull/10431 gets merged and backported to all supported versions @BuildStep - RuntimeInitializedClassBuildItem reinitializeClass() { - return new RuntimeInitializedClassBuildItem("sun.nio.ch.NioSocketImpl"); + RuntimeReinitializedClassBuildItem reinitializeClass() { + return new RuntimeReinitializedClassBuildItem("sun.nio.ch.NioSocketImpl"); } } From 68c5071f02952ea793c0ea1220d8adc461a66652 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Wed, 15 Jan 2025 15:30:55 +0200 Subject: [PATCH 3/3] Deprecate `RuntimeReinitializedClassBuildItem` Starting with Mandrel/GraalVM for JDK 21 `RuntimeReinitializedClassBuildItem` is functionally the same with `RuntimeInitializedClassBuildItem`. --- .../nativeimage/RuntimeReinitializedClassBuildItem.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/RuntimeReinitializedClassBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/RuntimeReinitializedClassBuildItem.java index 8ca45a2c62be2..d9ec805ef2463 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/RuntimeReinitializedClassBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/RuntimeReinitializedClassBuildItem.java @@ -5,7 +5,11 @@ /** * A class that will be reinitialized at runtime in native mode. This will result in the static * initializer running twice. + * + * @deprecated Starting with Mandrel/GraalVM 23.1 for JDK 21 this is functionally the same with + * {@link RuntimeInitializedClassBuildItem}. */ +@Deprecated(since = "3.18") public final class RuntimeReinitializedClassBuildItem extends MultiBuildItem { private final String className;