From 3c2c1dc026dd21e67e8369afa231ac1824d4d1f4 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Fri, 17 Sep 2021 14:45:00 +0300 Subject: [PATCH 1/2] Refactor: Move some MethodDescriptors to final fields to ease reuse --- .../steps/NativeImageAutoFeatureStep.java | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java index 5b136cd68bf8d..f3b8c6eab4e64 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java @@ -78,6 +78,13 @@ public class NativeImageAutoFeatureStep { private static final MethodDescriptor RESOURCES_REGISTRY_IGNORE_RESOURCES = ofMethod( "com.oracle.svm.core.configure.ResourcesRegistry", "ignoreResources", void.class, String.class); + private static final MethodDescriptor LOOKUP_METHOD = ofMethod( + "com.oracle.svm.util.ReflectionUtil", + "lookupMethod", Method.class, Class.class, String.class, Class[].class); + private static final MethodDescriptor FOR_NAME = ofMethod( + Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class); + private static final MethodDescriptor INVOKE = ofMethod( + Method.class, "invoke", Object.class, Object.class, Object[].class); static final String RUNTIME_REFLECTION = RuntimeReflection.class.getName(); static final String JNI_RUNTIME_ACCESS = "com.oracle.svm.core.jni.JNIRuntimeAccess"; static final String BEFORE_ANALYSIS_ACCESS = Feature.BeforeAnalysisAccess.class.getName(); @@ -538,39 +545,30 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class), currentThread); - MethodDescriptor forNameMethodDescriptor = ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, - ClassLoader.class); - - MethodDescriptor lookupMethod = ofMethod("com.oracle.svm.util.ReflectionUtil", "lookupMethod", Method.class, - Class.class, String.class, - Class[].class); - MethodDescriptor invokeMethodDescriptor = ofMethod(Method.class, "invoke", Object.class, Object.class, - Object[].class); - BranchResult graalVm21_3Test = tc.ifGreaterEqualZero( tc.invokeVirtualMethod(VERSION_COMPARE_TO, tc.invokeStaticMethod(VERSION_CURRENT), tc.marshalAsArray(int.class, tc.load(21), tc.load(3)))); BytecodeCreator greaterThan21_3 = graalVm21_3Test.trueBranch(); - ResultHandle runtimeSerializationClass = greaterThan21_3.invokeStaticMethod(forNameMethodDescriptor, + ResultHandle runtimeSerializationClass = greaterThan21_3.invokeStaticMethod(FOR_NAME, greaterThan21_3.load("org.graalvm.nativeimage.hosted.RuntimeSerialization"), greaterThan21_3.load(false), tccl); ResultHandle registerArgTypes = greaterThan21_3.newArray(Class.class, greaterThan21_3.load(1)); greaterThan21_3.writeArrayValue(registerArgTypes, 0, greaterThan21_3.loadClass(Class[].class)); - ResultHandle registerLookupMethod = greaterThan21_3.invokeStaticMethod(lookupMethod, runtimeSerializationClass, + ResultHandle registerLookupMethod = greaterThan21_3.invokeStaticMethod(LOOKUP_METHOD, runtimeSerializationClass, greaterThan21_3.load("register"), registerArgTypes); ResultHandle registerArgs = greaterThan21_3.newArray(Object.class, greaterThan21_3.load(1)); ResultHandle classesToRegister = greaterThan21_3.newArray(Class.class, greaterThan21_3.load(1)); greaterThan21_3.writeArrayValue(classesToRegister, 0, clazz); greaterThan21_3.writeArrayValue(registerArgs, 0, classesToRegister); - greaterThan21_3.invokeVirtualMethod(invokeMethodDescriptor, registerLookupMethod, + greaterThan21_3.invokeVirtualMethod(INVOKE, registerLookupMethod, greaterThan21_3.loadNull(), registerArgs); greaterThan21_3.returnValue(null); - ResultHandle serializationRegistryClass = tc.invokeStaticMethod(forNameMethodDescriptor, + ResultHandle serializationRegistryClass = tc.invokeStaticMethod(FOR_NAME, tc.load("com.oracle.svm.core.jdk.serialize.SerializationRegistry"), tc.load(false), tccl); - ResultHandle addReflectionsClass = tc.invokeStaticMethod(forNameMethodDescriptor, + ResultHandle addReflectionsClass = tc.invokeStaticMethod(FOR_NAME, tc.load("com.oracle.svm.reflect.serialize.hosted.SerializationFeature"), tc.load(false), tccl); @@ -581,7 +579,7 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator ResultHandle addReflectionsLookupArgs = tc.newArray(Class.class, tc.load(2)); tc.writeArrayValue(addReflectionsLookupArgs, 0, tc.loadClass(Class.class)); tc.writeArrayValue(addReflectionsLookupArgs, 1, tc.loadClass(Class.class)); - ResultHandle addReflectionsLookupMethod = tc.invokeStaticMethod(lookupMethod, addReflectionsClass, + ResultHandle addReflectionsLookupMethod = tc.invokeStaticMethod(LOOKUP_METHOD, addReflectionsClass, tc.load("addReflections"), addReflectionsLookupArgs); ResultHandle reflectionFactory = tc.invokeStaticMethod( @@ -589,9 +587,8 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator AssignableResultHandle newSerializationConstructor = tc.createVariable(Constructor.class); - ResultHandle externalizableClass = tc.invokeStaticMethod( - forNameMethodDescriptor, - tc.load("java.io.Externalizable"), tc.load(false), tccl); + ResultHandle externalizableClass = tc.invokeStaticMethod(FOR_NAME, tc.load("java.io.Externalizable"), tc.load(false), + tccl); BranchResult isExternalizable = tc .ifTrue(tc.invokeVirtualMethod(ofMethod(Class.class, "isAssignableFrom", boolean.class, Class.class), @@ -599,13 +596,11 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator BytecodeCreator ifIsExternalizable = isExternalizable.trueBranch(); ResultHandle array1 = ifIsExternalizable.newArray(Class.class, tc.load(1)); - ResultHandle classClass = ifIsExternalizable.invokeStaticMethod( - forNameMethodDescriptor, + ResultHandle classClass = ifIsExternalizable.invokeStaticMethod(FOR_NAME, ifIsExternalizable.load("java.lang.Class"), ifIsExternalizable.load(false), tccl); ifIsExternalizable.writeArrayValue(array1, 0, classClass); - ResultHandle externalizableLookupMethod = ifIsExternalizable.invokeStaticMethod( - lookupMethod, + ResultHandle externalizableLookupMethod = ifIsExternalizable.invokeStaticMethod(LOOKUP_METHOD, ifIsExternalizable.loadClass(ObjectStreamClass.class), ifIsExternalizable.load("getExternalizableConstructor"), array1); @@ -613,7 +608,7 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator ifIsExternalizable.writeArrayValue(array2, 0, clazz); ResultHandle externalizableConstructor = ifIsExternalizable.invokeVirtualMethod( - invokeMethodDescriptor, externalizableLookupMethod, ifIsExternalizable.loadNull(), array2); + INVOKE, externalizableLookupMethod, ifIsExternalizable.loadNull(), array2); ResultHandle externalizableConstructorClass = ifIsExternalizable.invokeVirtualMethod( ofMethod(Constructor.class, "getDeclaringClass", Class.class), @@ -622,7 +617,7 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator ResultHandle addReflectionsArgs1 = ifIsExternalizable.newArray(Class.class, tc.load(2)); ifIsExternalizable.writeArrayValue(addReflectionsArgs1, 0, clazz); ifIsExternalizable.writeArrayValue(addReflectionsArgs1, 1, externalizableConstructorClass); - ifIsExternalizable.invokeVirtualMethod(invokeMethodDescriptor, addReflectionsLookupMethod, + ifIsExternalizable.invokeVirtualMethod(INVOKE, addReflectionsLookupMethod, ifIsExternalizable.loadNull(), addReflectionsArgs1); ifIsExternalizable.returnValue(null); @@ -655,11 +650,11 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator newSerializationConstructor); ResultHandle getConstructorAccessor = tc.invokeStaticMethod( - lookupMethod, tc.loadClass(Constructor.class), tc.load("getConstructorAccessor"), + LOOKUP_METHOD, tc.loadClass(Constructor.class), tc.load("getConstructorAccessor"), tc.newArray(Class.class, tc.load(0))); ResultHandle accessor = tc.invokeVirtualMethod( - invokeMethodDescriptor, getConstructorAccessor, newSerializationConstructor, + INVOKE, getConstructorAccessor, newSerializationConstructor, tc.newArray(Object.class, tc.load(0))); tc.invokeVirtualMethod( @@ -669,7 +664,7 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator ResultHandle addReflectionsArgs2 = tc.newArray(Class.class, tc.load(2)); tc.writeArrayValue(addReflectionsArgs2, 0, clazz); tc.writeArrayValue(addReflectionsArgs2, 1, newSerializationConstructorClass); - tc.invokeVirtualMethod(invokeMethodDescriptor, addReflectionsLookupMethod, tc.loadNull(), addReflectionsArgs2); + tc.invokeVirtualMethod(INVOKE, addReflectionsLookupMethod, tc.loadNull(), addReflectionsArgs2); addSerializationForClass.returnValue(null); From b5361d8c2beb826be21d4f8e27b0df3ed4678b73 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Fri, 17 Sep 2021 14:53:55 +0300 Subject: [PATCH 2/2] Add GraalVM 21.3 compatibility support for resource registration oracle/graal#3774 changed the signature of ignoreResources as follows: ``` - public void ignoreResources(String pattern) { + public void ignoreResources(ConfigurationCondition condition, String pattern) { ``` This results in Quarkus throwing a `NoSuchMethodError` exception at the code generated by NativeImageAutoFeatureStep This patch looks for the right method based on the GraalVM/Mandrel version. Closes: #20226 --- .../steps/NativeImageAutoFeatureStep.java | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java index f3b8c6eab4e64..4f26a0b68e9f7 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java @@ -72,12 +72,6 @@ public class NativeImageAutoFeatureStep { private static final MethodDescriptor RERUN_INITIALIZATION = ofMethod( "org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport", "rerunInitialization", void.class, Class.class, String.class); - private static final MethodDescriptor RESOURCES_REGISTRY_ADD_RESOURCES = ofMethod( - "com.oracle.svm.core.configure.ResourcesRegistry", - "addResources", void.class, String.class); - private static final MethodDescriptor RESOURCES_REGISTRY_IGNORE_RESOURCES = ofMethod( - "com.oracle.svm.core.configure.ResourcesRegistry", - "ignoreResources", void.class, String.class); private static final MethodDescriptor LOOKUP_METHOD = ofMethod( "com.oracle.svm.util.ReflectionUtil", "lookupMethod", Method.class, Class.class, String.class, Class[].class); @@ -237,16 +231,63 @@ public void write(String s, byte[] bytes) { ResultHandle resourcesRegistrySingleton = overallCatch.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP, overallCatch.loadClass("com.oracle.svm.core.configure.ResourcesRegistry")); TryBlock tc = overallCatch.tryBlock(); + + ResultHandle currentThread = tc.invokeStaticMethod(ofMethod(Thread.class, "currentThread", Thread.class)); + ResultHandle tccl = tc.invokeVirtualMethod(ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class), + currentThread); + AssignableResultHandle resourcesArgTypes = tc.createVariable(Class[].class); + AssignableResultHandle resourcesArgs = tc.createVariable(Object[].class); + AssignableResultHandle argsIndex = tc.createVariable(int.class); + + BranchResult graalVm21_3Test = tc.ifGreaterEqualZero( + tc.invokeVirtualMethod(VERSION_COMPARE_TO, + tc.invokeStaticMethod(VERSION_CURRENT), + tc.marshalAsArray(int.class, tc.load(21), tc.load(3)))); + /* GraalVM >= 21.3 */ + BytecodeCreator greaterThan21_2 = graalVm21_3Test.trueBranch(); + ResultHandle argTypes = greaterThan21_2.newArray(Class.class, greaterThan21_2.load(2)); + ResultHandle configurationConditionClass = greaterThan21_2.invokeStaticMethod(FOR_NAME, + greaterThan21_2.load("org.graalvm.nativeimage.impl.ConfigurationCondition"), + greaterThan21_2.load(false), tccl); + greaterThan21_2.writeArrayValue(argTypes, 0, configurationConditionClass); + greaterThan21_2.writeArrayValue(argTypes, 1, greaterThan21_2.loadClass(String.class)); + greaterThan21_2.assign(resourcesArgTypes, argTypes); + ResultHandle args = greaterThan21_2.newArray(Object.class, greaterThan21_2.load(2)); + ResultHandle alwaysTrueMethod = greaterThan21_2.invokeStaticMethod(LOOKUP_METHOD, + configurationConditionClass, + greaterThan21_2.load("alwaysTrue"), + greaterThan21_2.newArray(Class.class, greaterThan21_2.load(0))); + ResultHandle alwaysTrueResult = greaterThan21_2.invokeVirtualMethod(INVOKE, + alwaysTrueMethod, greaterThan21_2.loadNull(), + greaterThan21_2.newArray(Object.class, greaterThan21_2.load(0))); + greaterThan21_2.writeArrayValue(args, 0, alwaysTrueResult); + greaterThan21_2.assign(resourcesArgs, args); + greaterThan21_2.assign(argsIndex, greaterThan21_2.load(1)); + + /* GraalVM < 21.3 */ + BytecodeCreator smallerThan21_3 = graalVm21_3Test.falseBranch(); + argTypes = smallerThan21_3.newArray(Class.class, smallerThan21_3.load(1)); + smallerThan21_3.writeArrayValue(argTypes, 0, smallerThan21_3.loadClass(String.class)); + smallerThan21_3.assign(resourcesArgTypes, argTypes); + args = smallerThan21_3.newArray(Object.class, smallerThan21_3.load(1)); + smallerThan21_3.assign(resourcesArgs, args); + smallerThan21_3.assign(argsIndex, smallerThan21_3.load(0)); + + ResultHandle ignoreResourcesMethod = tc.invokeStaticMethod(LOOKUP_METHOD, + tc.loadClass("com.oracle.svm.core.configure.ResourcesRegistry"), + tc.load("ignoreResources"), resourcesArgTypes); + ResultHandle addResourcesMethod = tc.invokeStaticMethod(LOOKUP_METHOD, + tc.loadClass("com.oracle.svm.core.configure.ResourcesRegistry"), + tc.load("addResources"), resourcesArgTypes); + for (NativeImageResourcePatternsBuildItem resourcePatternsItem : resourcePatterns) { for (String pattern : resourcePatternsItem.getExcludePatterns()) { - tc.invokeInterfaceMethod(RESOURCES_REGISTRY_IGNORE_RESOURCES, resourcesRegistrySingleton, - overallCatch.load(pattern)); + tc.writeArrayValue(resourcesArgs, argsIndex, tc.load(pattern)); + tc.invokeVirtualMethod(INVOKE, ignoreResourcesMethod, resourcesRegistrySingleton, resourcesArgs); } for (String pattern : resourcePatternsItem.getIncludePatterns()) { - tc.invokeInterfaceMethod( - RESOURCES_REGISTRY_ADD_RESOURCES, - resourcesRegistrySingleton, - tc.load(pattern)); + tc.writeArrayValue(resourcesArgs, argsIndex, tc.load(pattern)); + tc.invokeVirtualMethod(INVOKE, addResourcesMethod, resourcesRegistrySingleton, resourcesArgs); } } CatchBlockCreator cc = tc.addCatch(Throwable.class);