From 85a9cecc893e1f8a3f77e3fd586d6fb04bc9badf Mon Sep 17 00:00:00 2001 From: Loic Ottet Date: Mon, 18 Nov 2024 15:44:18 +0100 Subject: [PATCH 1/2] Register superclass serialization constructors by default --- .../org.graalvm.nativeimage/snapshot.sigtest | 1 + .../hosted/RuntimeSerialization.java | 8 +- .../impl/RuntimeSerializationSupport.java | 6 +- .../svm/agent/BreakpointInterceptor.java | 12 +-- .../test/config/OmitPreviousConfigTests.java | 4 +- .../config/SerializationConfiguration.java | 26 ++---- .../SerializationConfigurationType.java | 36 ++------ .../trace/SerializationProcessor.java | 4 +- ...egacySerializationConfigurationParser.java | 21 +++-- .../SerializationConfigurationParser.java | 5 +- .../SerializationMetadataParser.java | 12 ++- .../serialize/SerializationFeature.java | 92 +++++++------------ .../SubstrateGraphBuilderPlugins.java | 2 +- 13 files changed, 90 insertions(+), 139 deletions(-) diff --git a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest index ef23e446d560..6817c02d6f78 100644 --- a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest +++ b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest @@ -1143,6 +1143,7 @@ meth public !varargs static void registerProxyClass(java.lang.Class[]) meth public static void registerIncludingAssociatedClasses(java.lang.Class) meth public static void registerLambdaCapturingClass(java.lang.Class) meth public static void registerWithTargetConstructorClass(java.lang.Class,java.lang.Class) + anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="") supr java.lang.Object CLSS public final org.graalvm.nativeimage.hosted.RuntimeSystemProperties diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeSerialization.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeSerialization.java index 09d2c4a42e99..72efc04decf0 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeSerialization.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeSerialization.java @@ -81,7 +81,9 @@ public static void registerIncludingAssociatedClasses(Class clazz) { * @since 21.3 */ public static void register(Class... classes) { - RuntimeSerializationSupport.singleton().register(ConfigurationCondition.alwaysTrue(), classes); + for (Class clazz : classes) { + RuntimeSerializationSupport.singleton().register(ConfigurationCondition.alwaysTrue(), clazz); + } } /** @@ -95,8 +97,10 @@ public static void register(Class... classes) { * * @since 21.3 */ + @Deprecated + @SuppressWarnings("unused") public static void registerWithTargetConstructorClass(Class clazz, Class customTargetConstructorClazz) { - RuntimeSerializationSupport.singleton().registerWithTargetConstructorClass(ConfigurationCondition.alwaysTrue(), clazz, customTargetConstructorClazz); + RuntimeSerializationSupport.singleton().register(ConfigurationCondition.alwaysTrue(), clazz); } /** diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeSerializationSupport.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeSerializationSupport.java index 6cecab043977..3237047e86d8 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeSerializationSupport.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeSerializationSupport.java @@ -55,11 +55,9 @@ static RuntimeSerializationSupport singleton() { void registerIncludingAssociatedClasses(C condition, Class clazz); - void register(C condition, Class... classes); + void register(C condition, Class clazz); - void registerWithTargetConstructorClass(C condition, Class clazz, Class customTargetConstructorClazz); - - void registerWithTargetConstructorClass(C condition, String className, String customTargetConstructorClassName); + void register(C condition, String clazz); void registerLambdaCapturingClass(C condition, String lambdaCapturingClassName); diff --git a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java index 268e8129ad61..346e16fe3532 100644 --- a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java +++ b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java @@ -1102,7 +1102,7 @@ private static boolean readClassDescriptor(JNIEnvironment jni, JNIObjectHandle t name = nullHandle(); } var className = fromJniString(jni, name); - traceSerializeBreakpoint(jni, "ObjectInputStream.readClassDescriptor", true, state.getFullStackTraceOrNull(), className, null); + traceSerializeBreakpoint(jni, "ObjectInputStream.readClassDescriptor", true, state.getFullStackTraceOrNull(), className); return true; } @@ -1158,7 +1158,7 @@ private static boolean objectStreamClassConstructor(JNIEnvironment jni, JNIObjec Object interfaceNames = getClassArrayNames(jni, interfaces); traceSerializeBreakpoint(jni, "ProxyClassSerialization", validObjectStreamClassInstance, state.getFullStackTraceOrNull(), interfaceNames); } else { - traceSerializeBreakpoint(jni, "ObjectStreamClass.", validObjectStreamClassInstance, state.getFullStackTraceOrNull(), className, null); + traceSerializeBreakpoint(jni, "ObjectStreamClass.", validObjectStreamClassInstance, state.getFullStackTraceOrNull(), className); } } } @@ -1177,13 +1177,7 @@ private static boolean customTargetConstructorSerialization(JNIEnvironment jni, JNIObjectHandle serializeTargetClass = getObjectArgument(thread, 1); if (Support.isSerializable(jni, serializeTargetClass)) { String serializeTargetClassName = getClassNameOrNull(jni, serializeTargetClass); - - JNIObjectHandle customConstructorObj = getObjectArgument(thread, 2); - JNIObjectHandle customConstructorClass = jniFunctions().getGetObjectClass().invoke(jni, customConstructorObj); - JNIMethodId getDeclaringClassNameMethodID = agent.handles().getJavaLangReflectConstructorDeclaringClassName(jni, customConstructorClass); - JNIObjectHandle declaredClassNameObj = Support.callObjectMethod(jni, customConstructorObj, getDeclaringClassNameMethodID); - String customConstructorClassName = fromJniString(jni, declaredClassNameObj); - traceSerializeBreakpoint(jni, "ObjectStreamClass.", true, state.getFullStackTraceOrNull(), serializeTargetClassName, customConstructorClassName); + traceSerializeBreakpoint(jni, "ObjectStreamClass.", true, state.getFullStackTraceOrNull(), serializeTargetClassName); } return true; } diff --git a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java index d29330488c6e..b457990527b2 100644 --- a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java +++ b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java @@ -200,8 +200,8 @@ private static void doTestResourceConfig(ResourceConfiguration resourceConfig) { private static void doTestSerializationConfig(SerializationConfiguration serializationConfig) { UnresolvedConfigurationCondition condition = UnresolvedConfigurationCondition.alwaysTrue(); - Assert.assertFalse(serializationConfig.contains(condition, "seenType", null)); - Assert.assertTrue(serializationConfig.contains(condition, "unseenType", null)); + Assert.assertFalse(serializationConfig.contains(condition, "seenType")); + Assert.assertTrue(serializationConfig.contains(condition, "unseenType")); } private static ConfigurationType getConfigTypeOrFail(TypeConfiguration typeConfig, String typeName) { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java index 438fe8f50ab5..24df956eae32 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java @@ -99,12 +99,12 @@ protected void removeIf(Predicate predicate) { @Override public void mergeConditional(UnresolvedConfigurationCondition condition, SerializationConfiguration other) { for (SerializationConfigurationType type : other.serializations) { - serializations.add(new SerializationConfigurationType(condition, type.getQualifiedJavaName(), type.getQualifiedCustomTargetConstructorJavaName())); + serializations.add(new SerializationConfigurationType(condition, type.getQualifiedJavaName())); } } - public boolean contains(UnresolvedConfigurationCondition condition, String serializationTargetClass, String customTargetConstructorClass) { - return serializations.contains(createConfigurationType(condition, serializationTargetClass, customTargetConstructorClass)) || + public boolean contains(UnresolvedConfigurationCondition condition, String serializationTargetClass) { + return serializations.contains(createConfigurationType(condition, serializationTargetClass)) || lambdaSerializationCapturingTypes.contains(createLambdaCapturingClassConfigurationType(condition, serializationTargetClass)); } @@ -150,20 +150,13 @@ public void registerIncludingAssociatedClasses(UnresolvedConfigurationCondition } @Override - public void register(UnresolvedConfigurationCondition condition, Class... classes) { - for (Class clazz : classes) { - registerWithTargetConstructorClass(condition, clazz, null); - } - } - - @Override - public void registerWithTargetConstructorClass(UnresolvedConfigurationCondition condition, Class clazz, Class customTargetConstructorClazz) { - registerWithTargetConstructorClass(condition, clazz.getName(), customTargetConstructorClazz == null ? null : customTargetConstructorClazz.getName()); + public void register(UnresolvedConfigurationCondition condition, Class clazz) { + register(condition, clazz.getName()); } @Override - public void registerWithTargetConstructorClass(UnresolvedConfigurationCondition condition, String className, String customTargetConstructorClassName) { - serializations.add(createConfigurationType(condition, className, customTargetConstructorClassName)); + public void register(UnresolvedConfigurationCondition condition, String className) { + serializations.add(createConfigurationType(condition, className)); } @Override @@ -181,10 +174,9 @@ public boolean isEmpty() { return serializations.isEmpty() && lambdaSerializationCapturingTypes.isEmpty() && interfaceListsSerializableProxies.isEmpty(); } - private static SerializationConfigurationType createConfigurationType(UnresolvedConfigurationCondition condition, String className, String customTargetConstructorClassName) { + private static SerializationConfigurationType createConfigurationType(UnresolvedConfigurationCondition condition, String className) { String convertedClassName = SignatureUtil.toInternalClassName(className); - String convertedCustomTargetConstructorClassName = customTargetConstructorClassName == null ? null : SignatureUtil.toInternalClassName(customTargetConstructorClassName); - return new SerializationConfigurationType(condition, convertedClassName, convertedCustomTargetConstructorClassName); + return new SerializationConfigurationType(condition, convertedClassName); } private static SerializationConfigurationLambdaCapturingType createLambdaCapturingClassConfigurationType(UnresolvedConfigurationCondition condition, String className) { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java index bc6bc8fcadb0..99b429f4905b 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java @@ -24,45 +24,34 @@ */ package com.oracle.svm.configure.config; +import static com.oracle.svm.core.configure.ConfigurationParser.NAME_KEY; +import static com.oracle.svm.core.configure.ConfigurationParser.TYPE_KEY; + import java.io.IOException; -import java.util.Comparator; import java.util.Objects; import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; -import com.oracle.svm.core.configure.SerializationConfigurationParser; - import jdk.graal.compiler.util.json.JsonPrintable; import jdk.graal.compiler.util.json.JsonWriter; -import static com.oracle.svm.core.configure.ConfigurationParser.NAME_KEY; -import static com.oracle.svm.core.configure.ConfigurationParser.TYPE_KEY; - public class SerializationConfigurationType implements JsonPrintable, Comparable { private final UnresolvedConfigurationCondition condition; private final String qualifiedJavaName; - private final String qualifiedCustomTargetConstructorJavaName; - public SerializationConfigurationType(UnresolvedConfigurationCondition condition, String qualifiedJavaName, String qualifiedCustomTargetConstructorJavaName) { + public SerializationConfigurationType(UnresolvedConfigurationCondition condition, String qualifiedJavaName) { assert qualifiedJavaName.indexOf('/') == -1 : "Requires qualified Java name, not the internal representation"; assert !qualifiedJavaName.startsWith("[") : "Requires Java source array syntax, for example java.lang.String[]"; - assert qualifiedCustomTargetConstructorJavaName == null || qualifiedCustomTargetConstructorJavaName.indexOf('/') == -1 : "Requires qualified Java name, not internal representation"; - assert qualifiedCustomTargetConstructorJavaName == null || !qualifiedCustomTargetConstructorJavaName.startsWith("[") : "Requires Java source array syntax, for example java.lang.String[]"; Objects.requireNonNull(condition); this.condition = condition; Objects.requireNonNull(qualifiedJavaName); this.qualifiedJavaName = qualifiedJavaName; - this.qualifiedCustomTargetConstructorJavaName = qualifiedCustomTargetConstructorJavaName; } public String getQualifiedJavaName() { return qualifiedJavaName; } - public String getQualifiedCustomTargetConstructorJavaName() { - return qualifiedCustomTargetConstructorJavaName; - } - public UnresolvedConfigurationCondition getCondition() { return condition; } @@ -80,11 +69,6 @@ private void printJson(JsonWriter writer, boolean combinedFile) throws IOExcepti writer.appendObjectStart(); ConfigurationConditionPrintable.printConditionAttribute(condition, writer, combinedFile); writer.quote(combinedFile ? TYPE_KEY : NAME_KEY).appendFieldSeparator().quote(qualifiedJavaName); - if (qualifiedCustomTargetConstructorJavaName != null) { - writer.appendSeparator(); - writer.quote(SerializationConfigurationParser.CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY).appendFieldSeparator() - .quote(qualifiedCustomTargetConstructorJavaName); - } writer.appendObjectEnd(); } @@ -98,13 +82,12 @@ public boolean equals(Object o) { } SerializationConfigurationType that = (SerializationConfigurationType) o; return condition.equals(that.condition) && - qualifiedJavaName.equals(that.qualifiedJavaName) && - Objects.equals(qualifiedCustomTargetConstructorJavaName, that.qualifiedCustomTargetConstructorJavaName); + qualifiedJavaName.equals(that.qualifiedJavaName); } @Override public int hashCode() { - return Objects.hash(condition, qualifiedJavaName, qualifiedCustomTargetConstructorJavaName); + return Objects.hash(condition, qualifiedJavaName); } @Override @@ -113,11 +96,6 @@ public int compareTo(SerializationConfigurationType other) { if (compareName != 0) { return compareName; } - int compareCondition = condition.compareTo(other.condition); - if (compareCondition != 0) { - return compareCondition; - } - Comparator nullsFirstCompare = Comparator.nullsFirst(Comparator.naturalOrder()); - return nullsFirstCompare.compare(qualifiedCustomTargetConstructorJavaName, other.qualifiedCustomTargetConstructorJavaName); + return condition.compareTo(other.condition); } } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/SerializationProcessor.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/SerializationProcessor.java index 2ef063061a2b..d20a5cf0d131 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/SerializationProcessor.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/SerializationProcessor.java @@ -57,7 +57,7 @@ void processEntry(EconomicMap entry, ConfigurationSet configurationSe SerializationConfiguration serializationConfiguration = configurationSet.getSerializationConfiguration(); if ("ObjectStreamClass.".equals(function) || "ObjectInputStream.readClassDescriptor".equals(function)) { - expectSize(args, 2); + expectSize(args, 1); if (advisor.shouldIgnore(LazyValueUtils.lazyValue((String) args.get(0)), LazyValueUtils.lazyValue(null), false)) { return; @@ -68,7 +68,7 @@ void processEntry(EconomicMap entry, ConfigurationSet configurationSe if (className.contains(LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING)) { serializationConfiguration.registerLambdaCapturingClass(condition, className); } else { - serializationConfiguration.registerWithTargetConstructorClass(condition, className, (String) args.get(1)); + serializationConfiguration.register(condition, className); } } else if ("SerializedLambda.readResolve".equals(function)) { expectSize(args, 1); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacySerializationConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacySerializationConfigurationParser.java index 46c92f8b389c..bc4aeba5c112 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacySerializationConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacySerializationConfigurationParser.java @@ -33,6 +33,8 @@ import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; +import com.oracle.svm.util.LogUtils; + import jdk.graal.compiler.util.json.JsonParserException; final class LegacySerializationConfigurationParser extends SerializationConfigurationParser { @@ -79,6 +81,8 @@ private void parseNewConfiguration(EconomicMap listOfSerializati } } + private boolean customConstructorWarningTriggered = false; + @Override protected void parseSerializationDescriptorObject(EconomicMap data, boolean lambdaCapturingType) { if (lambdaCapturingType) { @@ -87,7 +91,7 @@ protected void parseSerializationDescriptorObject(EconomicMap da checkAttributes(data, "serialization descriptor object", Collections.singleton(NAME_KEY), Arrays.asList(CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY, CONDITIONAL_KEY)); } - ConfigurationTypeDescriptor targetSerializationClass = new NamedConfigurationTypeDescriptor(asString(data.get(NAME_KEY))); + NamedConfigurationTypeDescriptor targetSerializationClass = new NamedConfigurationTypeDescriptor(asString(data.get(NAME_KEY))); UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, false); var condition = conditionResolver.resolveCondition(unresolvedCondition); if (!condition.isPresent()) { @@ -95,18 +99,15 @@ protected void parseSerializationDescriptorObject(EconomicMap da } if (lambdaCapturingType) { - String className = ((NamedConfigurationTypeDescriptor) targetSerializationClass).name(); + String className = targetSerializationClass.name(); serializationSupport.registerLambdaCapturingClass(condition.get(), className); } else { - Object optionalCustomCtorValue = data.get(CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY); - String customTargetConstructorClass = optionalCustomCtorValue != null ? asString(optionalCustomCtorValue) : null; - if (targetSerializationClass instanceof NamedConfigurationTypeDescriptor namedClass) { - serializationSupport.registerWithTargetConstructorClass(condition.get(), namedClass.name(), customTargetConstructorClass); - } else if (targetSerializationClass instanceof ProxyConfigurationTypeDescriptor proxyClass) { - serializationSupport.registerProxyClass(condition.get(), proxyClass.interfaceNames()); - } else { - throw new JsonParserException("Unknown configuration type descriptor: %s".formatted(targetSerializationClass.toString())); + if (!customConstructorWarningTriggered && data.containsKey(CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY)) { + customConstructorWarningTriggered = true; + LogUtils.warning("\"" + CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY + + "\" is deprecated in serialization-config.json. All serializable classes can be instantiated through any superclass constructor without the use of the flag."); } + serializationSupport.register(condition.get(), targetSerializationClass.name()); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java index e34d651a3030..e79b76ed074f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java @@ -62,10 +62,9 @@ protected void parseSerializationTypes(List listOfSerializationTypes, bo protected abstract void parseSerializationDescriptorObject(EconomicMap data, boolean lambdaCapturingType); - protected void registerType(ConfigurationTypeDescriptor targetSerializationClass, C condition, Object optionalCustomCtorValue) { - String customTargetConstructorClass = optionalCustomCtorValue != null ? asString(optionalCustomCtorValue) : null; + protected void registerType(ConfigurationTypeDescriptor targetSerializationClass, C condition) { if (targetSerializationClass instanceof NamedConfigurationTypeDescriptor namedClass) { - serializationSupport.registerWithTargetConstructorClass(condition, namedClass.name(), customTargetConstructorClass); + serializationSupport.register(condition, namedClass.name()); } else if (targetSerializationClass instanceof ProxyConfigurationTypeDescriptor proxyClass) { serializationSupport.registerProxyClass(condition, proxyClass.interfaceNames()); } else { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationMetadataParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationMetadataParser.java index 9b74ed811243..cc20eb92e2da 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationMetadataParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationMetadataParser.java @@ -32,6 +32,8 @@ import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; +import com.oracle.svm.util.LogUtils; + final class SerializationMetadataParser extends SerializationConfigurationParser { SerializationMetadataParser(ConfigurationConditionResolver conditionResolver, RuntimeSerializationSupport serializationSupport, boolean strictConfiguration) { @@ -46,6 +48,8 @@ public void parseAndRegister(Object json, URI origin) { } } + private boolean customConstructorWarningTriggered = false; + @Override protected void parseSerializationDescriptorObject(EconomicMap data, boolean lambdaCapturingType) { checkAttributes(data, "serialization descriptor object", List.of(TYPE_KEY), List.of(CONDITIONAL_KEY, CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY)); @@ -61,7 +65,11 @@ protected void parseSerializationDescriptorObject(EconomicMap da return; } - Object optionalCustomCtorValue = data.get(CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY); - registerType(targetSerializationClass.get(), condition.get(), optionalCustomCtorValue); + if (!customConstructorWarningTriggered && data.containsKey(CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY)) { + customConstructorWarningTriggered = true; + LogUtils.warning("\"" + CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY + + "\" is deprecated in reachability-metadata.json. All serializable classes can be instantiated through any superclass constructor without the use of the flag."); + } + registerType(targetSerializationClass.get(), condition.get()); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java index 4335f139eb23..c878db324403 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java @@ -225,22 +225,15 @@ public void registerIncludingAssociatedClasses(ConfigurationCondition condition, } @Override - public void register(ConfigurationCondition condition, Class... classes) { - for (Class clazz : classes) { - registerWithTargetConstructorClass(condition, clazz, null); + public void register(ConfigurationCondition condition, Class clazz) { + if (clazz != null) { + deniedClasses.put(clazz, true); } } @Override - public void registerWithTargetConstructorClass(ConfigurationCondition condition, String className, String customTargetConstructorClassName) { - registerWithTargetConstructorClass(condition, typeResolver.resolveType(className), null); - } - - @Override - public void registerWithTargetConstructorClass(ConfigurationCondition condition, Class clazz, Class customTargetConstructorClazz) { - if (clazz != null) { - deniedClasses.put(clazz, true); - } + public void register(ConfigurationCondition condition, String className) { + this.register(condition, typeResolver.resolveType(className)); } @Override @@ -361,13 +354,6 @@ private void registerIncludingAssociatedClasses(ConfigurationCondition condition } } - @Override - public void register(ConfigurationCondition condition, Class... classes) { - for (Class clazz : classes) { - registerWithTargetConstructorClass(condition, clazz, null); - } - } - @Override public void registerLambdaCapturingClass(ConfigurationCondition condition, String lambdaCapturingClassName) { abortIfSealed(); @@ -394,12 +380,12 @@ public void registerLambdaCapturingClass(ConfigurationCondition condition, Strin public void registerProxyClass(ConfigurationCondition condition, List implementedInterfaces) { registerConditionalConfiguration(condition, (cnd) -> { Class proxyClass = proxyRegistry.createProxyClassForSerialization(implementedInterfaces); - registerWithTargetConstructorClass(cnd, proxyClass, Object.class); + register(cnd, proxyClass); }); } @Override - public void registerWithTargetConstructorClass(ConfigurationCondition condition, String targetClassName, String customTargetConstructorClassName) { + public void register(ConfigurationCondition condition, String targetClassName) { abortIfSealed(); Class serializationTargetClass = typeResolver.resolveType(targetClassName); /* With invalid streams we have to register the class for lookup */ @@ -407,20 +393,11 @@ public void registerWithTargetConstructorClass(ConfigurationCondition condition, if (serializationTargetClass == null) { return; } - - if (customTargetConstructorClassName != null) { - Class customTargetConstructorClass = typeResolver.resolveType(customTargetConstructorClassName); - if (customTargetConstructorClass == null) { - return; - } - registerWithTargetConstructorClass(condition, serializationTargetClass, customTargetConstructorClass); - } else { - registerWithTargetConstructorClass(condition, serializationTargetClass, null); - } + register(condition, serializationTargetClass); } @Override - public void registerWithTargetConstructorClass(ConfigurationCondition condition, Class serializationTargetClass, Class customTargetConstructorClass) { + public void register(ConfigurationCondition condition, Class serializationTargetClass) { abortIfSealed(); registerConditionalConfiguration(condition, (cnd) -> { /* @@ -439,18 +416,7 @@ public void registerWithTargetConstructorClass(ConfigurationCondition condition, RuntimeReflection.register(java.io.ObjectOutputStream.class); if (denyRegistry.isAllowed(serializationTargetClass)) { - if (customTargetConstructorClass != null) { - if (!customTargetConstructorClass.isAssignableFrom(serializationTargetClass)) { - LogUtils.warning("The given customTargetConstructorClass %s is not a superclass of the serialization target %s.", customTargetConstructorClass.getName(), - serializationTargetClass); - return; - } - if (ReflectionUtil.lookupConstructor(true, customTargetConstructorClass) == null) { - LogUtils.warning("The given customTargetConstructorClass %s does not declare a parameterless constructor.", customTargetConstructorClass.getName()); - return; - } - } - addOrQueueConstructorAccessor(cnd, serializationTargetClass, customTargetConstructorClass); + addOrQueueConstructorAccessors(cnd, serializationTargetClass); Class superclass = serializationTargetClass.getSuperclass(); if (superclass != null) { @@ -466,20 +432,28 @@ public void registerWithTargetConstructorClass(ConfigurationCondition condition, }); } - private void addOrQueueConstructorAccessor(ConfigurationCondition cnd, Class serializationTargetClass, Class customTargetConstructorClass) { + private void addOrQueueConstructorAccessors(ConfigurationCondition cnd, Class serializationTargetClass) { if (pendingConstructorRegistrations != null) { // cannot yet create constructor accessor -> add to pending - pendingConstructorRegistrations.add(() -> registerConstructorAccessor(cnd, serializationTargetClass, customTargetConstructorClass)); + pendingConstructorRegistrations.add(() -> registerConstructorAccessors(cnd, serializationTargetClass)); } else { // can already run the registration - registerConstructorAccessor(cnd, serializationTargetClass, customTargetConstructorClass); + registerConstructorAccessors(cnd, serializationTargetClass); } } - private void registerConstructorAccessor(ConfigurationCondition cnd, Class serializationTargetClass, Class customTargetConstructorClass) { - Optional.ofNullable(addConstructorAccessor(cnd, serializationTargetClass, customTargetConstructorClass)) + private void registerConstructorAccessors(ConfigurationCondition cnd, Class serializationTargetClass) { + serializationSupport.registerSerializationTargetClass(cnd, serializationTargetClass); + registerConstructorAccessor(cnd, serializationTargetClass, null); + for (Class superclass = serializationTargetClass; superclass != null; superclass = superclass.getSuperclass()) { + registerConstructorAccessor(cnd, serializationTargetClass, superclass); + } + } + + private void registerConstructorAccessor(ConfigurationCondition cnd, Class serializationTargetClass, Class targetConstructorClass) { + Optional.ofNullable(addConstructorAccessor(serializationTargetClass, targetConstructorClass)) .map(ReflectionUtil::lookupConstructor) - .ifPresent(methods -> ImageSingletons.lookup(RuntimeReflectionSupport.class).register(ConfigurationCondition.alwaysTrue(), false, methods)); + .ifPresent(methods -> ImageSingletons.lookup(RuntimeReflectionSupport.class).register(cnd, false, methods)); } void beforeAnalysis(Feature.BeforeAnalysisAccess beforeAnalysisAccess) { @@ -683,9 +657,7 @@ private static Constructor getExternalizableConstructor(Class serializatio return ReflectionUtil.invokeMethod(getExternalizableConstructorMethod, null, serializationTargetClass); } - private Class addConstructorAccessor(ConfigurationCondition cnd, Class serializationTargetClass, Class customTargetConstructorClass) { - serializationSupport.registerSerializationTargetClass(cnd, serializationTargetClass); - + private Class addConstructorAccessor(Class serializationTargetClass, Class customTargetConstructorClass) { // Don't generate SerializationConstructorAccessor class for Externalizable case if (Externalizable.class.isAssignableFrom(serializationTargetClass)) { try { @@ -706,13 +678,17 @@ private Class addConstructorAccessor(ConfigurationCondition cnd, Class ser VMError.guarantee(stubConstructor != null, "stubConstructor is null, calling this too early"); targetConstructor = stubConstructor; } else { - if (customTargetConstructorClass == serializationTargetClass) { - /* No custom constructor needed. Simply use existing no-arg constructor. */ - return customTargetConstructorClass; - } Constructor customConstructorToCall = null; if (customTargetConstructorClass != null) { - customConstructorToCall = ReflectionUtil.lookupConstructor(customTargetConstructorClass); + customConstructorToCall = ReflectionUtil.lookupConstructor(true, customTargetConstructorClass); + if (customConstructorToCall == null) { + /* No suitable constructor, no need to register */ + return null; + } + if (customTargetConstructorClass == serializationTargetClass) { + /* No custom constructor needed. Simply use existing no-arg constructor. */ + return customTargetConstructorClass; + } } targetConstructor = newConstructorForSerialization(serializationTargetClass, customConstructorToCall); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index e229c0a8be34..1bb561e5a132 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -260,7 +260,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec var clazz = asConstantObject(b, Class.class, clazzNode); var constructor = asConstantObject(b, Constructor.class, constructorNode); if (clazz != null && constructor != null) { - b.add(ReachabilityRegistrationNode.create(() -> RuntimeSerialization.registerWithTargetConstructorClass(clazz, constructor.getDeclaringClass()), reason)); + b.add(ReachabilityRegistrationNode.create(() -> RuntimeSerialization.register(clazz), reason)); return true; } return false; From c6b920032fd7cc3203e209cb6d1d58c7325538eb Mon Sep 17 00:00:00 2001 From: Loic Ottet Date: Sun, 1 Dec 2024 23:15:00 +0100 Subject: [PATCH 2/2] Register reflectively-accessed types as unsafe allocated --- .../nativeimage/impl/ReflectionRegistry.java | 4 ++-- .../configure/config/ConfigurationType.java | 7 ------- .../config/ParserConfigurationAdapter.java | 6 ------ .../svm/configure/trace/JniProcessor.java | 6 +++--- .../configure/trace/ReflectionProcessor.java | 3 ++- .../LegacyReflectionConfigurationParser.java | 9 ++++++++- .../ReflectionConfigurationParserDelegate.java | 2 -- .../configure/ReflectionMetadataParser.java | 10 ++++++++-- .../svm/hosted/config/RegistryAdapter.java | 12 ------------ .../svm/hosted/jni/JNIAccessFeature.java | 5 ++--- .../hosted/reflect/ReflectionDataBuilder.java | 18 +++++++++--------- 11 files changed, 34 insertions(+), 48 deletions(-) diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ReflectionRegistry.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ReflectionRegistry.java index 9d0534347cfb..86aaa584abce 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ReflectionRegistry.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ReflectionRegistry.java @@ -46,10 +46,10 @@ public interface ReflectionRegistry { default void register(ConfigurationCondition condition, Class... classes) { - Arrays.stream(classes).forEach(clazz -> register(condition, false, clazz)); + Arrays.stream(classes).forEach(clazz -> register(condition, clazz)); } - void register(ConfigurationCondition condition, boolean unsafeAllocated, Class clazz); + void register(ConfigurationCondition condition, Class clazz); void register(ConfigurationCondition condition, boolean queriedOnly, Executable... methods); diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java index 39d0bcf00ca1..1a82086747df 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java @@ -100,7 +100,6 @@ static ConfigurationType copyAndMerge(ConfigurationType type, ConfigurationType private boolean allPublicClasses; private ConfigurationMemberAccessibility allDeclaredFieldsAccess = ConfigurationMemberAccessibility.NONE; private ConfigurationMemberAccessibility allPublicFieldsAccess = ConfigurationMemberAccessibility.NONE; - private boolean unsafeAllocated; private ConfigurationMemberAccessibility allDeclaredMethodsAccess = ConfigurationMemberAccessibility.NONE; private ConfigurationMemberAccessibility allPublicMethodsAccess = ConfigurationMemberAccessibility.NONE; private ConfigurationMemberAccessibility allDeclaredConstructorsAccess = ConfigurationMemberAccessibility.NONE; @@ -281,7 +280,6 @@ private void setFlagsFromOther(ConfigurationType other, BiPredicate methodParameterTypes) { VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/JniProcessor.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/JniProcessor.java index 8c973e41fc6b..d9fb941e909d 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/JniProcessor.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/JniProcessor.java @@ -89,10 +89,10 @@ void processEntry(EconomicMap entry, ConfigurationSet configurationSe case "AllocObject": expectSize(args, 0); /* - * AllocObject is implemented via Unsafe.allocateInstance, so we need to set the - * "unsafe allocated" flag in the reflection configuration file. + * AllocObject is implemented via Unsafe.allocateInstance, so we need to add the + * type to the reflection configuration file. */ - configurationSet.getReflectionConfiguration().getOrCreateType(condition, clazz).setUnsafeAllocated(); + configurationSet.getReflectionConfiguration().getOrCreateType(condition, clazz); break; case "GetStaticMethodID": case "GetMethodID": { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/ReflectionProcessor.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/ReflectionProcessor.java index 9788d607c0bc..fc8e2ccfdb37 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/ReflectionProcessor.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/ReflectionProcessor.java @@ -283,7 +283,8 @@ public void processEntry(EconomicMap entry, ConfigurationSet configur break; } case "allocateInstance": { - configuration.getOrCreateType(condition, clazz).setUnsafeAllocated(); + /* Reflectively-accessed types are unsafe-allocatable by default */ + configuration.getOrCreateType(condition, clazz); break; } default: diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyReflectionConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyReflectionConfigurationParser.java index a123418dc670..c919fa61018d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyReflectionConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyReflectionConfigurationParser.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Optional; +import com.oracle.svm.util.LogUtils; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.MapCursor; import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; @@ -56,6 +57,8 @@ public void parseAndRegister(Object json, URI origin) { parseClassArray(asList(json, "first level of document must be an array of class descriptors")); } + private boolean unsafeAllocatedWarningTriggered = false; + @Override protected void parseClass(EconomicMap data) { checkAttributes(data, "reflection class descriptor object", List.of(NAME_KEY), OPTIONAL_REFLECT_CONFIG_OBJECT_ATTRS); @@ -93,6 +96,11 @@ protected void parseClass(EconomicMap data) { T clazz = result.get(); delegate.registerType(conditionResult.get(), clazz); + if (!unsafeAllocatedWarningTriggered && data.containsKey("unsafeAllocated")) { + unsafeAllocatedWarningTriggered = true; + LogUtils.warning("\"unsafeAllocated\" is deprecated in reflection-config.json. All reflectively-accessed classes can be instantiated through unsafe without the use of the flag."); + } + registerIfNotDefault(data, false, clazz, "allDeclaredConstructors", () -> delegate.registerDeclaredConstructors(condition, false, clazz)); registerIfNotDefault(data, false, clazz, "allPublicConstructors", () -> delegate.registerPublicConstructors(condition, false, clazz)); registerIfNotDefault(data, false, clazz, "allDeclaredMethods", () -> delegate.registerDeclaredMethods(condition, false, clazz)); @@ -117,7 +125,6 @@ protected void parseClass(EconomicMap data) { delegate.registerDeclaredFields(queryCondition, true, clazz); delegate.registerPublicFields(queryCondition, true, clazz); } - registerIfNotDefault(data, false, clazz, "unsafeAllocated", () -> delegate.registerUnsafeAllocated(condition, clazz)); MapCursor cursor = data.getEntries(); while (cursor.advance()) { String name = cursor.getKey(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParserDelegate.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParserDelegate.java index 748262afabb7..78cac38bd80c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParserDelegate.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParserDelegate.java @@ -68,8 +68,6 @@ public interface ReflectionConfigurationParserDelegate { boolean registerAllConstructors(C condition, boolean queriedOnly, T type); - void registerUnsafeAllocated(C condition, T clazz); - String getTypeName(T type); String getSimpleName(T type); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionMetadataParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionMetadataParser.java index 33bd0028be6c..ae1f30e3e23e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionMetadataParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionMetadataParser.java @@ -34,6 +34,7 @@ import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; import com.oracle.svm.core.TypeResult; +import com.oracle.svm.util.LogUtils; class ReflectionMetadataParser extends ReflectionConfigurationParser { private static final List OPTIONAL_REFLECT_METADATA_ATTRS = Arrays.asList(CONDITIONAL_KEY, @@ -56,6 +57,8 @@ public void parseAndRegister(Object json, URI origin) { } } + private boolean unsafeAllocatedWarningTriggered = false; + @Override protected void parseClass(EconomicMap data) { checkAttributes(data, "reflection class descriptor object", List.of(TYPE_KEY), OPTIONAL_REFLECT_METADATA_ATTRS); @@ -84,7 +87,7 @@ protected void parseClass(EconomicMap data) { C queryCondition = conditionResolver.alwaysTrue(); T clazz = result.get(); - delegate.registerType(conditionResult.get(), clazz); + delegate.registerType(condition, clazz); delegate.registerDeclaredClasses(queryCondition, clazz); delegate.registerRecordComponents(queryCondition, clazz); @@ -98,6 +101,10 @@ protected void parseClass(EconomicMap data) { delegate.registerPublicMethods(queryCondition, true, clazz); delegate.registerDeclaredFields(queryCondition, true, clazz); delegate.registerPublicFields(queryCondition, true, clazz); + if (!unsafeAllocatedWarningTriggered && data.containsKey("unsafeAllocated")) { + unsafeAllocatedWarningTriggered = true; + LogUtils.warning("\"unsafeAllocated\" is deprecated in reachability-metadata.json. All reflectively-accessed classes can be instantiated through unsafe without the use of the flag."); + } registerIfNotDefault(data, false, clazz, "allDeclaredConstructors", () -> delegate.registerDeclaredConstructors(condition, false, clazz)); registerIfNotDefault(data, false, clazz, "allPublicConstructors", () -> delegate.registerPublicConstructors(condition, false, clazz)); @@ -105,7 +112,6 @@ protected void parseClass(EconomicMap data) { registerIfNotDefault(data, false, clazz, "allPublicMethods", () -> delegate.registerPublicMethods(condition, false, clazz)); registerIfNotDefault(data, false, clazz, "allDeclaredFields", () -> delegate.registerDeclaredFields(condition, false, clazz)); registerIfNotDefault(data, false, clazz, "allPublicFields", () -> delegate.registerPublicFields(condition, false, clazz)); - registerIfNotDefault(data, false, clazz, "unsafeAllocated", () -> delegate.registerUnsafeAllocated(condition, clazz)); MapCursor cursor = data.getEntries(); while (cursor.advance()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/RegistryAdapter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/RegistryAdapter.java index 76ea23a764d6..72ac0f18d279 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/RegistryAdapter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/RegistryAdapter.java @@ -28,7 +28,6 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; @@ -223,17 +222,6 @@ public boolean registerAllConstructors(ConfigurationCondition condition, boolean return methods.length > 0; } - @Override - public void registerUnsafeAllocated(ConfigurationCondition condition, Class clazz) { - if (!clazz.isArray() && !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) { - registry.register(condition, true, clazz); - /* - * Ignore otherwise as the implementation of allocateInstance will anyhow throw an - * exception. - */ - } - } - @Override public void registerMethod(ConfigurationCondition condition, boolean queriedOnly, Class type, String methodName, List> methodParameterTypes) throws NoSuchMethodException { try { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java index c79b30e0ab31..287b6692e8b5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java @@ -219,8 +219,7 @@ private class JNIRuntimeAccessibilitySupportImpl extends ConditionalConfiguratio implements RuntimeJNIAccessSupport { @Override - public void register(ConfigurationCondition condition, boolean unsafeAllocated, Class clazz) { - assert !unsafeAllocated : "unsafeAllocated can be only set via Unsafe.allocateInstance, not via JNI."; + public void register(ConfigurationCondition condition, Class clazz) { Objects.requireNonNull(clazz, () -> nullErrorMessage("class")); abortIfSealed(); registerConditionalConfiguration(condition, (cnd) -> newClasses.add(clazz)); @@ -252,7 +251,7 @@ private void registerFields(boolean finalIsWritable, Field[] fields) { @Override public void registerClassLookup(ConfigurationCondition condition, String typeName) { try { - register(condition, false, Class.forName(typeName)); + register(condition, Class.forName(typeName)); } catch (ClassNotFoundException e) { newNegativeClassLookups.add(typeName); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java index 5b6941dc6bf0..824f6b796271 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java @@ -197,9 +197,9 @@ private boolean isQueryFlagSet(Class clazz, int flag) { } @Override - public void register(ConfigurationCondition condition, boolean unsafeInstantiated, Class clazz) { + public void register(ConfigurationCondition condition, Class clazz) { Objects.requireNonNull(clazz, () -> nullErrorMessage("class")); - runConditionalInAnalysisTask(condition, (cnd) -> registerClass(cnd, clazz, unsafeInstantiated, true)); + runConditionalInAnalysisTask(condition, (cnd) -> registerClass(cnd, clazz, true)); } @Override @@ -213,7 +213,7 @@ public void registerAllClassesQuery(ConfigurationCondition condition, Class c /* Malformed inner classes can have no declaring class */ innerClasses.computeIfAbsent(innerClass.getDeclaringClass(), c -> ConcurrentHashMap.newKeySet()).add(innerClass); } - registerClass(cnd, innerClass, false, !MissingRegistrationUtils.throwMissingRegistrationErrors()); + registerClass(cnd, innerClass, !MissingRegistrationUtils.throwMissingRegistrationErrors()); } } catch (LinkageError e) { registerLinkageError(clazz, e, classLookupExceptions); @@ -239,7 +239,7 @@ public void registerAllDeclaredClassesQuery(ConfigurationCondition condition, Cl try { for (Class innerClass : clazz.getDeclaredClasses()) { innerClasses.computeIfAbsent(clazz, c -> ConcurrentHashMap.newKeySet()).add(innerClass); - registerClass(cnd, innerClass, false, !MissingRegistrationUtils.throwMissingRegistrationErrors()); + registerClass(cnd, innerClass, !MissingRegistrationUtils.throwMissingRegistrationErrors()); } } catch (LinkageError e) { registerLinkageError(clazz, e, classLookupExceptions); @@ -247,14 +247,14 @@ public void registerAllDeclaredClassesQuery(ConfigurationCondition condition, Cl }); } - private void registerClass(ConfigurationCondition condition, Class clazz, boolean unsafeInstantiated, boolean allowForName) { + private void registerClass(ConfigurationCondition condition, Class clazz, boolean allowForName) { if (shouldExcludeClass(clazz)) { return; } AnalysisType type = metaAccess.lookupJavaType(clazz); type.registerAsReachable("Is registered for reflection."); - if (unsafeInstantiated) { + if (type.isArray() || (type.isInstanceClass() && !type.isAbstract())) { type.registerAsUnsafeAllocated("Is registered via reflection metadata."); classForNameSupport.registerUnsafeAllocated(condition, clazz); } @@ -291,7 +291,7 @@ public void registerClassLookupException(ConfigurationCondition condition, Strin public void registerClassLookup(ConfigurationCondition condition, String typeName) { runConditionalInAnalysisTask(condition, (cnd) -> { try { - registerClass(cnd, Class.forName(typeName, false, ClassLoader.getSystemClassLoader()), false, true); + registerClass(cnd, Class.forName(typeName, false, ClassLoader.getSystemClassLoader()), true); } catch (ClassNotFoundException e) { classForNameSupport.registerNegativeQuery(cnd, typeName); } catch (Throwable t) { @@ -316,7 +316,7 @@ public void registerAllPermittedSubclassesQuery(ConfigurationCondition condition setQueryFlag(clazz, ALL_PERMITTED_SUBCLASSES_FLAG); if (clazz.isSealed()) { for (Class permittedSubclass : clazz.getPermittedSubclasses()) { - registerClass(condition, permittedSubclass, false, false); + registerClass(condition, permittedSubclass, false); } } }); @@ -329,7 +329,7 @@ public void registerAllNestMembersQuery(ConfigurationCondition condition, Class< setQueryFlag(clazz, ALL_NEST_MEMBERS_FLAG); for (Class nestMember : clazz.getNestMembers()) { if (nestMember != clazz) { - registerClass(condition, nestMember, false, false); + registerClass(condition, nestMember, false); } } });