Skip to content

Commit 5844f34

Browse files
committed
New plugins for strict mode inference.
1 parent 398670a commit 5844f34

File tree

7 files changed

+634
-155
lines changed

7 files changed

+634
-155
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import java.util.regex.Pattern;
5656
import java.util.stream.Collectors;
5757

58+
import com.oracle.svm.hosted.dynamicaccessinference.StrictDynamicAccessInferenceFeature;
5859
import org.graalvm.nativeimage.ImageSingletons;
5960
import org.graalvm.nativeimage.hosted.RuntimeResourceAccess;
6061
import org.graalvm.nativeimage.impl.ConfigurationCondition;
@@ -672,7 +673,7 @@ public void beforeCompilation(BeforeCompilationAccess access) {
672673

673674
@Override
674675
public void registerInvocationPlugins(Providers providers, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) {
675-
if (!reason.duringAnalysis() || reason == ParsingReason.JITCompilation) {
676+
if (!reason.duringAnalysis() || reason == ParsingReason.JITCompilation || StrictDynamicAccessInferenceFeature.isEnforced()) {
676677
return;
677678
}
678679

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dynamicaccessinference/StrictDynamicAccessInferenceFeature.java

Lines changed: 5 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,8 @@
2424
*/
2525
package com.oracle.svm.hosted.dynamicaccessinference;
2626

27-
import java.lang.invoke.MethodType;
2827
import java.lang.reflect.Field;
29-
import java.lang.reflect.InvocationHandler;
30-
import java.util.function.BooleanSupplier;
31-
import java.util.function.Predicate;
3228

33-
import com.oracle.svm.core.ParsingReason;
3429
import org.graalvm.nativeimage.ImageSingletons;
3530
import org.graalvm.nativeimage.hosted.RuntimeReflection;
3631

@@ -43,51 +38,7 @@
4338

4439
import jdk.graal.compiler.options.Option;
4540
import jdk.graal.compiler.options.OptionStability;
46-
import jdk.vm.ci.meta.ResolvedJavaMethod;
47-
48-
/**
49-
* Feature which enables a graph IR optimization independent analysis of compile-time inferrable
50-
* method invocations which require dynamic access and would otherwise require a manual reachability
51-
* registration.
52-
* <p>
53-
* The targeted methods are:
54-
* <ul>
55-
* <li>{@link java.lang.Class#forName(String)}</li>
56-
* <li>{@link java.lang.Class#forName(String, boolean, ClassLoader)}</li>
57-
* <li>{@link java.lang.Class#getField(String)}</li>
58-
* <li>{@link java.lang.Class#getDeclaredField(String)}</li>
59-
* <li>{@link java.lang.Class#getConstructor(Class[])}</li>
60-
* <li>{@link java.lang.Class#getDeclaredConstructor(Class[])}</li>
61-
* <li>{@link java.lang.Class#getMethod(String, Class[])}</li>
62-
* <li>{@link java.lang.Class#getDeclaredMethod(String, Class[])}</li>
63-
* <li>{@link java.lang.Class#getFields()}</li>
64-
* <li>{@link java.lang.Class#getDeclaredFields()}</li>
65-
* <li>{@link java.lang.Class#getConstructors()}</li>
66-
* <li>{@link java.lang.Class#getDeclaredConstructors()}</li>
67-
* <li>{@link java.lang.Class#getMethods()}</li>
68-
* <li>{@link java.lang.Class#getDeclaredMethods()}</li>
69-
* <li>{@link java.lang.Class#getClasses()}</li>
70-
* <li>{@link java.lang.Class#getDeclaredClasses()}</li>
71-
* <li>{@link java.lang.Class#getNestMembers()}</li>
72-
* <li>{@link java.lang.Class#getPermittedSubclasses()}</li>
73-
* <li>{@link java.lang.Class#getRecordComponents()}</li>
74-
* <li>{@link java.lang.Class#getSigners()}</li>
75-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findClass(String)}}</li>
76-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findVirtual(Class, String, MethodType)}}</li>
77-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findStatic(Class, String, MethodType)}}</li>
78-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findConstructor(Class, MethodType)}}</li>
79-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findGetter(Class, String, Class)}}</li>
80-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findStaticGetter(Class, String, Class)}}</li>
81-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findSetter(Class, String, Class)}}</li>
82-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findStaticSetter(Class, String, Class)}}</li>
83-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findVarHandle(Class, String, Class)}}</li>
84-
* <li>{@link java.lang.invoke.MethodHandles.Lookup#findStaticVarHandle(Class, String, Class)}}</li>
85-
* <li>{@link java.lang.Class#getResource(String)}</li>
86-
* <li>{@link java.lang.Class#getResourceAsStream(String)}</li>
87-
* <li>{@link java.io.ObjectInputFilter.Config#createFilter(String)}</li>
88-
* <li>{@link java.lang.reflect.Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)}</li>
89-
* </ul>
90-
*/
41+
9142
@AutomaticallyRegisteredFeature
9243
public class StrictDynamicAccessInferenceFeature implements InternalFeature {
9344

@@ -112,6 +63,10 @@ public static boolean isActive() {
11263
return Options.StrictDynamicAccessInference.getValue() != Options.Mode.Disable;
11364
}
11465

66+
public static boolean isEnforced() {
67+
return Options.StrictDynamicAccessInference.getValue() == Options.Mode.Enforce;
68+
}
69+
11570
@Override
11671
public boolean isInConfiguration(IsInConfigurationAccess access) {
11772
return isActive();
@@ -127,9 +82,6 @@ public void afterRegistration(AfterRegistrationAccess access) {
12782

12883
ImageSingletons.add(ConstantExpressionRegistry.class, registry);
12984
ImageSingletons.add(StrictDynamicAccessInferenceSupport.class, support);
130-
131-
cacheMode(Options.StrictDynamicAccessInference.getValue());
132-
cacheRegistry(registry);
13385
}
13486

13587
@Override
@@ -167,47 +119,4 @@ public void afterAnalysis(AfterAnalysisAccess access) {
167119
*/
168120
ConstantExpressionRegistry.singleton().seal();
169121
}
170-
171-
private static void cacheMode(Options.Mode mode) {
172-
cachedMode = mode;
173-
}
174-
175-
private static void cacheRegistry(ConstantExpressionRegistry registry) {
176-
cachedRegistry = registry;
177-
}
178-
179-
private static Options.Mode cachedMode = Options.Mode.Disable;
180-
private static ConstantExpressionRegistry cachedRegistry = null;
181-
182-
/**
183-
* Utility method which attempts to infer {@code targetMethod} according to the {@code Disable},
184-
* {@code Warn} and {@code Enforce} options of {@code StrictConstantAnalysis}.
185-
*/
186-
public static boolean tryToInfer(ParsingReason reason, Predicate<ConstantExpressionRegistry> strictModeRoutine, BooleanSupplier graphModeRoutine, ResolvedJavaMethod targetMethod,
187-
Predicate<ResolvedJavaMethod> strictModeTarget) {
188-
/*
189-
* Do not restrict the folding of reflective calls if not building graphs for the analysis.
190-
*/
191-
if (!reason.duringAnalysis() || reason == ParsingReason.JITCompilation) {
192-
return graphModeRoutine.getAsBoolean();
193-
}
194-
boolean isTarget = strictModeTarget.test(targetMethod);
195-
if (cachedMode != Options.Mode.Disable && isTarget) {
196-
if (strictModeRoutine.test(cachedRegistry)) {
197-
return true;
198-
}
199-
}
200-
if (cachedMode != Options.Mode.Enforce || !isTarget) {
201-
return graphModeRoutine.getAsBoolean();
202-
}
203-
return false;
204-
}
205-
206-
/**
207-
* Utility method which attempts to infer {@code targetMethod} according to the {@code Disable},
208-
* {@code Warn} and {@code Enforce} options of {@code StrictConstantAnalysis}.
209-
*/
210-
public static boolean tryToInfer(ParsingReason reason, Predicate<ConstantExpressionRegistry> strictModeRoutine, BooleanSupplier graphModeRoutine) {
211-
return tryToInfer(reason, strictModeRoutine, graphModeRoutine, null, (method) -> true);
212-
}
213122
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.hosted.dynamicaccessinference;
26+
27+
import java.lang.reflect.InvocationHandler;
28+
import java.lang.reflect.Method;
29+
import java.lang.reflect.Proxy;
30+
import java.util.List;
31+
32+
import org.graalvm.nativeimage.hosted.Feature;
33+
import org.graalvm.nativeimage.hosted.RuntimeProxyCreation;
34+
35+
import com.oracle.svm.core.ParsingReason;
36+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
37+
import com.oracle.svm.core.feature.InternalFeature;
38+
import com.oracle.svm.hosted.ReachabilityRegistrationNode;
39+
import com.oracle.svm.util.ReflectionUtil;
40+
41+
import jdk.graal.compiler.nodes.ValueNode;
42+
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
43+
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
44+
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
45+
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
46+
import jdk.graal.compiler.phases.util.Providers;
47+
import jdk.vm.ci.meta.ResolvedJavaMethod;
48+
49+
@AutomaticallyRegisteredFeature
50+
public class StrictProxyInferenceFeature implements InternalFeature {
51+
52+
private ConstantExpressionRegistry registry;
53+
54+
@Override
55+
public List<Class<? extends Feature>> getRequiredFeatures() {
56+
return List.of(StrictDynamicAccessInferenceFeature.class);
57+
}
58+
59+
@Override
60+
public boolean isInConfiguration(IsInConfigurationAccess access) {
61+
StrictDynamicAccessInferenceFeature.Options.Mode mode = StrictDynamicAccessInferenceFeature.Options.StrictDynamicAccessInference.getValue();
62+
return mode == StrictDynamicAccessInferenceFeature.Options.Mode.Enforce;
63+
}
64+
65+
@Override
66+
public void duringSetup(DuringSetupAccess access) {
67+
registry = ConstantExpressionRegistry.singleton();
68+
}
69+
70+
@Override
71+
public void registerInvocationPlugins(Providers providers, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) {
72+
if (reason != ParsingReason.PointsToAnalysis) {
73+
return;
74+
}
75+
76+
InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
77+
78+
Method getProxyClass = ReflectionUtil.lookupMethod(Proxy.class, "getProxyClass", ClassLoader.class, Class[].class);
79+
Method newProxyInstance = ReflectionUtil.lookupMethod(Proxy.class, "newProxyInstance", ClassLoader.class, Class[].class, InvocationHandler.class);
80+
81+
for (Method method : List.of(getProxyClass, newProxyInstance)) {
82+
invocationPlugins.register(method.getDeclaringClass(), new InvocationPlugin.RequiredInvocationPlugin(method.getName(), method.getParameterTypes()) {
83+
@Override
84+
public boolean isDecorator() {
85+
return true;
86+
}
87+
88+
@Override
89+
public boolean defaultHandler(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... args) {
90+
Class<?>[] interfaces = registry.getArgument(b.getMethod(), b.bci(), targetMethod, 1, Class[].class);
91+
return registerProxy(b, reason, interfaces);
92+
}
93+
});
94+
}
95+
}
96+
97+
private boolean registerProxy(GraphBuilderContext b, ParsingReason reason, Class<?>[] interfaces) {
98+
if (interfaces == null) {
99+
return false;
100+
}
101+
102+
b.add(ReachabilityRegistrationNode.create(() -> RuntimeProxyCreation.register(interfaces), reason));
103+
return true;
104+
}
105+
}

0 commit comments

Comments
 (0)