Skip to content

Commit

Permalink
Use the scoping mechanism for the dynamic proxy plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksandar Gradinac authored and loicottet committed Apr 6, 2023
1 parent 4f424a9 commit 6e571cd
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import com.oracle.svm.core.option.OptionClassFilter;

public class MissingRegistrationSupport {

private final OptionClassFilter classFilter;

@Platforms(Platform.HOSTED_ONLY.class)
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,15 @@
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;
import com.oracle.graal.pointsto.nodes.UnsafePartitionLoadNode;
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;
Expand Down Expand Up @@ -175,9 +177,6 @@ public class SubstrateGraphBuilderPlugins {
public static class Options {
@Option(help = "Enable trace logging for dynamic proxy.")//
public static final HostedOptionKey<Boolean> DynamicProxyTracing = new HostedOptionKey<>(false);

@Option(help = "Check reachability before automatically registering proxies observed in the code.")//
public static final HostedOptionKey<Boolean> StrictProxyAutoRegistration = new HostedOptionKey<>(false);
}

public static void registerInvocationPlugins(AnnotationSubstitutionProcessor annotationSubstitutions,
Expand Down Expand Up @@ -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)) {
Expand All @@ -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;
}

/**
Expand Down

0 comments on commit 6e571cd

Please sign in to comment.