From e21b5e7eaf434a606560c3e0336239c20696d7cd Mon Sep 17 00:00:00 2001 From: Strahinja Stanojevic Date: Tue, 18 Apr 2023 09:59:27 +0200 Subject: [PATCH] Enable proxy class serialization test. Add assertion that predefined classes must not have a class loader during registration. --- .../svm/core/hub/PredefinedClassesSupport.java | 14 ++++++++++++++ .../svm/hosted/ClassPredefinitionFeature.java | 10 ++++++++++ .../test/proxy/ProxyClassSerializationTest.java | 7 +++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/PredefinedClassesSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/PredefinedClassesSupport.java index 7914ae10520f..5af9235c696f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/PredefinedClassesSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/PredefinedClassesSupport.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; @@ -67,6 +68,8 @@ public static final class Options { public static final String ENABLE_BYTECODES_OPTION = SubstrateOptionsParser.commandArgument(Options.SupportPredefinedClasses, "+"); + @Platforms(Platform.HOSTED_ONLY.class) private Consumer> validator = null; + @Fold public static boolean supportsBytecodes() { return Options.SupportPredefinedClasses.getValue(); @@ -111,8 +114,16 @@ static PredefinedClassesSupport singleton() { /** Predefined classes which have already been loaded, by name. */ private final EconomicMap> loadedClassesByName = EconomicMap.create(); + @Platforms(Platform.HOSTED_ONLY.class) + public void setRegistrationValidator(Consumer> consumer) { + validator = consumer; + } + @Platforms(Platform.HOSTED_ONLY.class) public static void registerClass(String hash, Class clazz) { + if (singleton().validator != null) { + singleton().validator.accept(clazz); + } Class existing = singleton().predefinedClassesByHash.putIfAbsent(hash, clazz); if (existing != clazz) { VMError.guarantee(existing == null, "Can define only one class per hash"); @@ -167,6 +178,9 @@ private static void registerLambdaForReflection(Class lambdaClass) { */ @Platforms(Platform.HOSTED_ONLY.class) public static void registerClass(Class clazz) { + if (singleton().validator != null) { + singleton().validator.accept(clazz); + } singleton().predefinedClasses.add(clazz); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassPredefinitionFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassPredefinitionFeature.java index 3003f6370a5f..0aa2d92bb2e1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassPredefinitionFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassPredefinitionFeature.java @@ -36,12 +36,14 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationFiles; import com.oracle.svm.core.configure.PredefinedClassesConfigurationParser; @@ -100,6 +102,14 @@ public void afterRegistration(AfterRegistrationAccess arg) { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { + FeatureImpl.BeforeAnalysisAccessImpl impl = (FeatureImpl.BeforeAnalysisAccessImpl) access; + PredefinedClassesSupport support = ImageSingletons.lookup(PredefinedClassesSupport.class); + support.setRegistrationValidator(clazz -> { + Optional analysisType = impl.getMetaAccess().optionalLookupJavaType(clazz); + analysisType.map(impl.getHostVM()::dynamicHub).ifPresent( + hub -> VMError.guarantee(hub.isLoaded(), "Classes that should be predefined must not have a class loader.")); + }); + sealed = true; List skipped = new ArrayList<>(); diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/proxy/ProxyClassSerializationTest.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/proxy/ProxyClassSerializationTest.java index 6a2c1d59bbcf..f86cb7edcb06 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/proxy/ProxyClassSerializationTest.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/proxy/ProxyClassSerializationTest.java @@ -25,6 +25,8 @@ package com.oracle.svm.test.proxy; +import org.junit.Test; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -39,10 +41,6 @@ import java.util.List; import java.util.Set; -/** - * FIXME: Temporary workaround for GR-40265. Test will be re-enabled as soon as the solution for - * this problem is found. - */ public class ProxyClassSerializationTest { private static void serialize(ByteArrayOutputStream byteArrayOutputStream, Object proxyObject) throws IOException { @@ -57,6 +55,7 @@ private static Object deserialize(ByteArrayOutputStream byteArrayOutputStream) t return objectInputStream.readObject(); } + @Test public void testProxyClassSerialization() throws Exception { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();