From 6e571cd28b50c2913311e78b1f1498762b6bf677 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Wed, 29 Mar 2023 18:13:39 +0200 Subject: [PATCH] Use the scoping mechanism for the dynamic proxy plugin --- .../svm/core/MissingRegistrationSupport.java | 7 +- .../oracle/svm/hosted/ResourcesFeature.java | 2 +- .../serialize/SerializationFeature.java | 10 +-- .../SubstrateGraphBuilderPlugins.java | 67 +++++++++---------- 4 files changed, 41 insertions(+), 45 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MissingRegistrationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MissingRegistrationSupport.java index 009389c4cc95b..55d6257aafaa1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MissingRegistrationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MissingRegistrationSupport.java @@ -32,7 +32,6 @@ import com.oracle.svm.core.option.OptionClassFilter; public class MissingRegistrationSupport { - private final OptionClassFilter classFilter; @Platforms(Platform.HOSTED_ONLY.class) @@ -46,7 +45,11 @@ public static MissingRegistrationSupport singleton() { } public boolean reportMissingRegistrationErrors(StackTraceElement responsibleClass) { - return classFilter.isIncluded(responsibleClass.getModuleName(), getPackageName(responsibleClass.getClassName()), responsibleClass.getClassName()) != null; + return reportMissingRegistrationErrors(responsibleClass.getModuleName(), getPackageName(responsibleClass.getClassName()), responsibleClass.getClassName()); + } + + public boolean reportMissingRegistrationErrors(String moduleName, String packageName, String className) { + return classFilter.isIncluded(moduleName, packageName, className) != null; } private static String getPackageName(String className) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java index 6939b4a8ac909..2c55c5dc1ab82 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java @@ -455,8 +455,8 @@ public boolean isDecorator() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { try { if (!sealed && receiver.isConstant() && arg.isJavaConstant() && !arg.isNullConstant()) { - String resource = snippetReflectionProvider.asObject(String.class, arg.asJavaConstant()); Class clazz = snippetReflectionProvider.asObject(Class.class, receiver.get().asJavaConstant()); + String resource = snippetReflectionProvider.asObject(String.class, arg.asJavaConstant()); String resourceName = (String) resolveResourceName.invoke(clazz, resource); b.add(new ReachabilityRegistrationNode(() -> RuntimeResourceAccess.addResource(clazz.getModule(), resourceName))); return true; 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 70f1e3d09ad14..fb2d6ee04524e 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 @@ -71,7 +71,6 @@ import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; import com.oracle.graal.pointsto.util.GraalAccess; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.configure.ConditionalElement; import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationFiles; @@ -535,13 +534,8 @@ private static void registerForSerialization(Class serializationTargetClass) * serialization class consistency, so need to register all constructors, methods and * fields. */ - if (SubstrateOptions.ThrowMissingRegistrationErrors.hasBeenSet()) { - RuntimeReflection.registerAsQueried(serializationTargetClass.getDeclaredConstructors()); - RuntimeReflection.registerAsQueried(serializationTargetClass.getDeclaredMethods()); - } else { - RuntimeReflection.register(serializationTargetClass.getDeclaredConstructors()); - RuntimeReflection.register(serializationTargetClass.getDeclaredMethods()); - } + RuntimeReflection.register(serializationTargetClass.getDeclaredConstructors()); + RuntimeReflection.register(serializationTargetClass.getDeclaredMethods()); RuntimeReflection.register(serializationTargetClass.getDeclaredFields()); } 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 8f80b102f3829..7bc4423ba523d 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 @@ -110,6 +110,7 @@ import org.graalvm.word.UnsignedWord; import com.oracle.graal.pointsto.AbstractAnalysisEngine; +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -117,6 +118,7 @@ import com.oracle.graal.pointsto.nodes.UnsafePartitionStoreNode; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.MissingRegistrationSupport; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.RuntimeAssertionsSupport; @@ -175,9 +177,6 @@ public class SubstrateGraphBuilderPlugins { public static class Options { @Option(help = "Enable trace logging for dynamic proxy.")// public static final HostedOptionKey DynamicProxyTracing = new HostedOptionKey<>(false); - - @Option(help = "Check reachability before automatically registering proxies observed in the code.")// - public static final HostedOptionKey StrictProxyAutoRegistration = new HostedOptionKey<>(false); } public static void registerInvocationPlugins(AnnotationSubstitutionProcessor annotationSubstitutions, @@ -415,44 +414,52 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec private static void registerProxyPlugins(SnippetReflectionProvider snippetReflection, AnnotationSubstitutionProcessor annotationSubstitutions, InvocationPlugins plugins, ParsingReason reason) { if (SubstrateOptions.parseOnce() || reason.duringAnalysis()) { Registration proxyRegistration = new Registration(plugins, Proxy.class); - proxyRegistration.register(new RequiredInvocationPlugin("getProxyClass", ClassLoader.class, Class[].class) { - @Override - public boolean isDecorator() { - return Options.StrictProxyAutoRegistration.getValue(); - } + registerProxyPlugin(proxyRegistration, snippetReflection, annotationSubstitutions, "getProxyClass", ClassLoader.class, Class[].class); + registerProxyPlugin(proxyRegistration, snippetReflection, annotationSubstitutions, "newProxyInstance", ClassLoader.class, Class[].class, InvocationHandler.class); + } + } - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode classLoaderNode, ValueNode interfacesNode) { - return interceptProxyInterfaces(b, targetMethod, snippetReflection, annotationSubstitutions, interfacesNode); - } - }); + private static void registerProxyPlugin(Registration proxyRegistration, SnippetReflectionProvider snippetReflection, AnnotationSubstitutionProcessor annotationSubstitutions, String name, + Class... parameterTypes) { + proxyRegistration.register(new RequiredInvocationPlugin(name, parameterTypes) { + @Override + public boolean isDecorator() { + return true; + } - proxyRegistration.register(new RequiredInvocationPlugin("newProxyInstance", ClassLoader.class, Class[].class, InvocationHandler.class) { - @Override - public boolean isDecorator() { - return Options.StrictProxyAutoRegistration.getValue(); - } + @Override + public boolean defaultHandler(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... args) { + Runnable proxyRegistrationRunnable = interceptProxyInterfaces(b, targetMethod, snippetReflection, annotationSubstitutions, args[1]); + if (proxyRegistrationRunnable != null) { + Class callerClass = OriginalClassProvider.getJavaClass(b.getMethod().getDeclaringClass()); + boolean callerInScope = MissingRegistrationSupport.singleton().reportMissingRegistrationErrors(callerClass.getModule().getName(), callerClass.getPackageName(), + callerClass.getName()); + if (callerInScope) { + b.add(new ReachabilityRegistrationNode(proxyRegistrationRunnable)); + return true; + } - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode classLoaderNode, ValueNode interfacesNode, ValueNode invocationHandlerNode) { - return interceptProxyInterfaces(b, targetMethod, snippetReflection, annotationSubstitutions, interfacesNode); + proxyRegistrationRunnable.run(); + return false; } - }); - } + return false; + } + }); } /** * Try to intercept proxy interfaces passed in as literal constants, and register the interfaces * in the {@link DynamicProxyRegistry}. */ - private static boolean interceptProxyInterfaces(GraphBuilderContext b, ResolvedJavaMethod targetMethod, SnippetReflectionProvider snippetReflection, + private static Runnable interceptProxyInterfaces(GraphBuilderContext b, ResolvedJavaMethod targetMethod, SnippetReflectionProvider snippetReflection, AnnotationSubstitutionProcessor annotationSubstitutions, ValueNode interfacesNode) { Class[] interfaces = extractClassArray(b, snippetReflection, annotationSubstitutions, interfacesNode); if (interfaces != null) { var caller = b.getGraph().method(); var method = b.getMethod(); var bci = b.bci(); - Runnable registerProxy = () -> { + + return () -> { /* The interfaces array can be empty. The java.lang.reflect.Proxy API allows it. */ RuntimeProxyCreation.register(interfaces); if (ImageSingletons.contains(FallbackFeature.class)) { @@ -463,20 +470,12 @@ private static boolean interceptProxyInterfaces(GraphBuilderContext b, ResolvedJ " reached from " + caller.format("%H.%n(%p)") + ". " + "Registered proxy class for " + Arrays.toString(interfaces) + "."); } }; - - if (Options.StrictProxyAutoRegistration.getValue()) { - b.add(new ReachabilityRegistrationNode(registerProxy)); - return true; - } - - registerProxy.run(); - return false; } if (Options.DynamicProxyTracing.getValue() && !b.parsingIntrinsic()) { System.out.println("Could not determine constant value for interfaces argument of call to " + targetMethod.format("%H.%n(%p)") + " reached from " + b.getGraph().method().format("%H.%n(%p)") + "."); } - return false; + return null; } /**