From e7f1750a3cf59f6f8d4813abda2070c52d2eb733 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Fri, 13 Aug 2021 00:15:33 +0300 Subject: [PATCH] SerializationRegistry and addReflections moved in GraalVM 21.3-dev https://github.com/oracle/graal/pull/3050 introduces a number of changes around the internal APIs that are being used by Quarkus to register classes for serialization thus breaking serialization support when using 21.3-dev These changes are: 1. `SerializationRegistry` class has been moved from `com.oracle.svm.core.jdk.serialize` to `com.oracle.svm.reflect.serialize` 2. `addReflections` method moved from `com.oracle.svm.reflect.serialize.hosted.SerializationFeature` to `com.oracle.svm.reflect.serialize.hosted.SerializationBuilder` and became `private` https://github.com/oracle/graal/pull/3050 also introduces `SerializationFeature.register(Class... classes)` which is available as a public API (not internal) and can save us from having to keep up with the internal APIs as new releases come out. This PR leverages the new API to register classes for serialization when using GraalVM/Mandrel >=21.3. Closes https://github.com/quarkusio/quarkus/issues/19338 --- .../steps/NativeImageAutoFeatureStep.java | 86 +++++++++++++------ 1 file changed, 60 insertions(+), 26 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 dacefc389d66c4..342cd2b98b7a62 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 @@ -538,13 +538,53 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class), currentThread); - ResultHandle objectClass = tc.invokeStaticMethod( - ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class), - tc.load("java.lang.Object"), tc.load(false), tccl); + 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, + 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, + 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.loadNull(), registerArgs); + greaterThan21_3.returnValue(null); + + ResultHandle objectClass = tc.invokeStaticMethod(forNameMethodDescriptor, tc.load("java.lang.Object"), + tc.load(false), tccl); + ResultHandle serializationRegistryClass = tc.invokeStaticMethod(forNameMethodDescriptor, + tc.load("com.oracle.svm.core.jdk.serialize.SerializationRegistry"), + tc.load(false), tccl); + ResultHandle addReflectionsClass = tc.invokeStaticMethod(forNameMethodDescriptor, + tc.load("com.oracle.svm.reflect.serialize.hosted.SerializationFeature"), + tc.load(false), tccl); ResultHandle serializationSupport = tc.invokeStaticMethod( IMAGE_SINGLETONS_LOOKUP, - tc.loadClass("com.oracle.svm.core.jdk.serialize.SerializationRegistry")); + serializationRegistryClass); + + 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, + tc.load("addReflections"), addReflectionsLookupArgs); ResultHandle reflectionFactory = tc.invokeStaticMethod( ofMethod("sun.reflect.ReflectionFactory", "getReflectionFactory", "sun.reflect.ReflectionFactory")); @@ -552,7 +592,7 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator AssignableResultHandle newSerializationConstructor = tc.createVariable(Constructor.class); ResultHandle externalizableClass = tc.invokeStaticMethod( - ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class), + forNameMethodDescriptor, tc.load("java.io.Externalizable"), tc.load(false), tccl); BranchResult isExternalizable = tc @@ -562,13 +602,12 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator ResultHandle array1 = ifIsExternalizable.newArray(Class.class, tc.load(1)); ResultHandle classClass = ifIsExternalizable.invokeStaticMethod( - ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class), + forNameMethodDescriptor, ifIsExternalizable.load("java.lang.Class"), ifIsExternalizable.load(false), tccl); ifIsExternalizable.writeArrayValue(array1, 0, classClass); ResultHandle externalizableLookupMethod = ifIsExternalizable.invokeStaticMethod( - ofMethod("com.oracle.svm.util.ReflectionUtil", "lookupMethod", Method.class, Class.class, String.class, - Class[].class), + lookupMethod, ifIsExternalizable.loadClass(ObjectStreamClass.class), ifIsExternalizable.load("getExternalizableConstructor"), array1); @@ -576,18 +615,17 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator ifIsExternalizable.writeArrayValue(array2, 0, clazz); ResultHandle externalizableConstructor = ifIsExternalizable.invokeVirtualMethod( - ofMethod(Method.class, "invoke", Object.class, Object.class, - Object[].class), - externalizableLookupMethod, ifIsExternalizable.loadNull(), array2); + invokeMethodDescriptor, externalizableLookupMethod, ifIsExternalizable.loadNull(), array2); ResultHandle externalizableConstructorClass = ifIsExternalizable.invokeVirtualMethod( ofMethod(Constructor.class, "getDeclaringClass", Class.class), externalizableConstructor); - ifIsExternalizable.invokeStaticMethod( - ofMethod("com.oracle.svm.reflect.serialize.hosted.SerializationFeature", "addReflections", void.class, - Class.class, Class.class), - clazz, externalizableConstructorClass); + ResultHandle addRedlectionsArgs1 = ifIsExternalizable.newArray(Class.class, tc.load(2)); + ifIsExternalizable.writeArrayValue(addRedlectionsArgs1, 0, clazz); + ifIsExternalizable.writeArrayValue(addRedlectionsArgs1, 1, externalizableConstructorClass); + ifIsExternalizable.invokeVirtualMethod(invokeMethodDescriptor, addReflectionsLookupMethod, + ifIsExternalizable.loadNull(), addRedlectionsArgs1); ifIsExternalizable.returnValue(null); @@ -618,26 +656,22 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator ofMethod(Constructor.class, "getDeclaringClass", Class.class), newSerializationConstructor); - ResultHandle lookupMethod = tc.invokeStaticMethod( - ofMethod("com.oracle.svm.util.ReflectionUtil", "lookupMethod", Method.class, Class.class, String.class, - Class[].class), - tc.loadClass(Constructor.class), tc.load("getConstructorAccessor"), + ResultHandle getConstructorAccessor = tc.invokeStaticMethod( + lookupMethod, tc.loadClass(Constructor.class), tc.load("getConstructorAccessor"), tc.newArray(Class.class, tc.load(0))); ResultHandle accessor = tc.invokeVirtualMethod( - ofMethod(Method.class, "invoke", Object.class, Object.class, - Object[].class), - lookupMethod, newSerializationConstructor, + invokeMethodDescriptor, getConstructorAccessor, newSerializationConstructor, tc.newArray(Object.class, tc.load(0))); tc.invokeVirtualMethod( ofMethod("com.oracle.svm.reflect.serialize.SerializationSupport", "addConstructorAccessor", Object.class, Class.class, Class.class, Object.class), serializationSupport, clazz, newSerializationConstructorClass, accessor); - tc.invokeStaticMethod( - ofMethod("com.oracle.svm.reflect.serialize.hosted.SerializationFeature", "addReflections", void.class, - Class.class, Class.class), - clazz, objectClass); + ResultHandle addRedlectionsArgs2 = tc.newArray(Class.class, tc.load(2)); + tc.writeArrayValue(addRedlectionsArgs2, 0, clazz); + tc.writeArrayValue(addRedlectionsArgs2, 1, objectClass); + tc.invokeVirtualMethod(invokeMethodDescriptor, addReflectionsLookupMethod, tc.loadNull(), addRedlectionsArgs2); addSerializationForClass.returnValue(null);