Skip to content

Commit dcb55a2

Browse files
committed
Change phase to take method parameters into consideration for more fine grained analysis and future stale entry matching
1 parent b0c04d6 commit dcb55a2

File tree

1 file changed

+189
-99
lines changed

1 file changed

+189
-99
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/DynamicAccessDetectionPhase.java

Lines changed: 189 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -32,32 +32,34 @@
3232
import jdk.graal.compiler.nodes.java.MethodCallTargetNode;
3333
import jdk.graal.compiler.nodes.spi.CoreProviders;
3434
import jdk.graal.compiler.phases.BasePhase;
35-
import jdk.internal.loader.BuiltinClassLoader;
36-
import jdk.internal.loader.Loader;
37-
import jdk.vm.ci.meta.ResolvedJavaType;
38-
import sun.invoke.util.ValueConversions;
39-
import sun.invoke.util.VerifyAccess;
40-
import sun.security.x509.X500Name;
41-
import sun.util.locale.provider.LocaleProviderAdapter;
35+
import jdk.vm.ci.meta.JavaType;
36+
import jdk.vm.ci.meta.Signature;
4237

4338
import java.io.ObjectInputStream;
4439
import java.io.ObjectOutputStream;
4540
import java.io.ObjectStreamClass;
4641
import java.lang.invoke.ConstantBootstraps;
42+
import java.lang.invoke.MethodHandle;
4743
import java.lang.invoke.MethodHandleProxies;
4844
import java.lang.invoke.MethodHandles;
45+
import java.lang.invoke.MethodType;
4946
import java.lang.invoke.VarHandle;
5047
import java.lang.reflect.Array;
5148
import java.lang.reflect.Constructor;
49+
import java.lang.reflect.Field;
50+
import java.lang.reflect.InvocationHandler;
5251
import java.lang.reflect.Method;
5352
import java.lang.reflect.Proxy;
5453
import java.net.URISyntaxException;
5554
import java.net.URL;
56-
import java.net.URLClassLoader;
5755
import java.security.CodeSource;
56+
import java.util.ArrayList;
57+
import java.util.Arrays;
5858
import java.util.HashMap;
5959
import java.util.List;
60+
import java.util.Locale;
6061
import java.util.Map;
62+
import java.util.Objects;
6163
import java.util.ResourceBundle;
6264
import java.util.Set;
6365
import java.util.random.RandomGeneratorFactory;
@@ -83,96 +85,134 @@ public enum DynamicAccessKind {
8385
}
8486
}
8587

86-
public record MethodInfo(DynamicAccessKind accessKind, String name) {
88+
public record MethodInfo(DynamicAccessKind accessKind, String signature) {
8789
}
8890

89-
private static final Map<Class<?>, Set<String>> reflectionMethodNames = new HashMap<>();
90-
private static final Map<Class<?>, Set<String>> resourceMethodNames = new HashMap<>();
91+
private static final Map<Class<?>, Set<MethodSignature>> reflectionMethodSignatures = new HashMap<>();
92+
private static final Map<Class<?>, Set<MethodSignature>> resourceMethodSignatures = new HashMap<>();
9193

9294
private final DynamicAccessDetectionFeature dynamicAccessDetectionFeature;
9395

9496
static {
95-
reflectionMethodNames.put(Class.class, Set.of(
96-
"forName",
97-
"getClasses",
98-
"getDeclaredClasses",
99-
"getConstructor",
100-
"getConstructors",
101-
"getDeclaredConstructor",
102-
"getDeclaredConstructors",
103-
"getField",
104-
"getFields",
105-
"getDeclaredField",
106-
"getDeclaredFields",
107-
"getMethod",
108-
"getMethods",
109-
"getDeclaredMethod",
110-
"getDeclaredMethods",
111-
"getNestMembers",
112-
"getPermittedSubclasses",
113-
"getRecordComponents",
114-
"getSigners",
115-
"arrayType",
116-
"newInstance"));
117-
reflectionMethodNames.put(Method.class, Set.of("invoke"));
118-
reflectionMethodNames.put(MethodHandles.Lookup.class, Set.of(
119-
"findClass",
120-
"findVirtual",
121-
"findStatic",
122-
"findConstructor",
123-
"findSpecial",
124-
"findGetter",
125-
"findSetter",
126-
"findStaticGetter",
127-
"findStaticSetter",
128-
"findVarHandle",
129-
"findStaticVarHandle",
130-
"unreflect",
131-
"unreflectSpecial",
132-
"unreflectConstructor",
133-
"unreflectGetter",
134-
"unreflectSetter",
135-
"unreflectVarHandle"));
136-
reflectionMethodNames.put(ClassLoader.class, Set.of(
137-
"loadClass",
138-
"findBootstrapClassOrNull",
139-
"findLoadedClass",
140-
"findSystemClass"));
141-
reflectionMethodNames.put(URLClassLoader.class, Set.of("loadClass"));
142-
reflectionMethodNames.put(Array.class, Set.of("newInstance"));
143-
reflectionMethodNames.put(Constructor.class, Set.of("newInstance"));
144-
reflectionMethodNames.put(VerifyAccess.class, Set.of("isTypeVisible"));
145-
reflectionMethodNames.put(LocaleProviderAdapter.class, Set.of("forType"));
146-
reflectionMethodNames.put(ValueConversions.class, Set.of("boxExact"));
147-
reflectionMethodNames.put(ConstantBootstraps.class, Set.of(
148-
"getStaticFinal",
149-
"staticFieldVarHandle",
150-
"fieldVarHandle"));
151-
reflectionMethodNames.put(VarHandle.VarHandleDesc.class, Set.of("resolveConstantDesc"));
152-
reflectionMethodNames.put(RandomGeneratorFactory.class, Set.of("create"));
153-
reflectionMethodNames.put(X500Name.class, Set.of("asX500Principal"));
154-
reflectionMethodNames.put(MethodHandleProxies.class, Set.of("asInterfaceInstance"));
97+
reflectionMethodSignatures.put(Class.class, Set.of(
98+
new MethodSignature("forName", String.class),
99+
new MethodSignature("forName", String.class, boolean.class, ClassLoader.class),
100+
new MethodSignature("forName", Module.class, String.class),
101+
new MethodSignature("getClasses"),
102+
new MethodSignature("getDeclaredClasses"),
103+
new MethodSignature("getConstructor", Class[].class),
104+
new MethodSignature("getConstructors"),
105+
new MethodSignature("getDeclaredConstructor", Class[].class),
106+
new MethodSignature("getDeclaredConstructors"),
107+
new MethodSignature("getField", String.class),
108+
new MethodSignature("getFields"),
109+
new MethodSignature("getDeclaredField", String.class),
110+
new MethodSignature("getDeclaredFields"),
111+
new MethodSignature("getMethod", String.class, Class[].class),
112+
new MethodSignature("getMethods"),
113+
new MethodSignature("getDeclaredMethod", String.class, Class[].class),
114+
new MethodSignature("getDeclaredMethods"),
115+
new MethodSignature("getNestMembers"),
116+
new MethodSignature("getPermittedSubclasses"),
117+
new MethodSignature("getRecordComponents"),
118+
new MethodSignature("getSigners"),
119+
new MethodSignature("arrayType"),
120+
new MethodSignature("newInstance")
121+
));
122+
reflectionMethodSignatures.put(Method.class, Set.of(
123+
new MethodSignature("invoke", Object.class, Object[].class)
124+
));
125+
reflectionMethodSignatures.put(MethodHandles.Lookup.class, Set.of(
126+
new MethodSignature("findClass", String.class),
127+
new MethodSignature("findVirtual", Class.class, String.class, MethodType.class),
128+
new MethodSignature("findStatic", Class.class, String.class, MethodType.class),
129+
new MethodSignature("findConstructor", Class.class, MethodType.class),
130+
new MethodSignature("findSpecial", Class.class, String.class, MethodType.class, Class.class),
131+
new MethodSignature("findGetter", Class.class, String.class, Class.class),
132+
new MethodSignature("findSetter", Class.class, String.class, Class.class),
133+
new MethodSignature("findStaticGetter", Class.class, String.class, Class.class),
134+
new MethodSignature("findStaticSetter", Class.class, String.class, Class.class),
135+
new MethodSignature("findVarHandle", Class.class, String.class, Class.class),
136+
new MethodSignature("findStaticVarHandle", Class.class, String.class, Class.class),
137+
new MethodSignature("unreflect", Method.class),
138+
new MethodSignature("unreflectSpecial", Method.class, Class.class),
139+
new MethodSignature("unreflectConstructor", Constructor.class),
140+
new MethodSignature("unreflectGetter", Field.class),
141+
new MethodSignature("unreflectSetter", Field.class),
142+
new MethodSignature("unreflectVarHandle", Field.class)
143+
));
144+
reflectionMethodSignatures.put(ClassLoader.class, Set.of(
145+
new MethodSignature("loadClass", String.class),
146+
new MethodSignature("findLoadedClass", String.class),
147+
new MethodSignature("findSystemClass", String.class)
148+
));
149+
reflectionMethodSignatures.put(Array.class, Set.of(
150+
new MethodSignature("newInstance", Class.class, int.class),
151+
new MethodSignature("newInstance", Class.class, int[].class)
152+
));
153+
reflectionMethodSignatures.put(Constructor.class, Set.of(
154+
new MethodSignature("newInstance", Object[].class)
155+
));
156+
reflectionMethodSignatures.put(ConstantBootstraps.class, Set.of(
157+
new MethodSignature("getStaticFinal", MethodHandles.Lookup.class, String.class, Class.class, Class.class),
158+
new MethodSignature("getStaticFinal", MethodHandles.Lookup.class, String.class, Class.class),
159+
new MethodSignature("fieldVarHandle", MethodHandles.Lookup.class, String.class, Class.class, Class.class, Class.class),
160+
new MethodSignature("staticFieldVarHandle", MethodHandles.Lookup.class, String.class, Class.class, Class.class, Class.class)
161+
));
162+
reflectionMethodSignatures.put(VarHandle.VarHandleDesc.class, Set.of(
163+
new MethodSignature("resolveConstantDesc", MethodHandles.Lookup.class)
164+
));
165+
reflectionMethodSignatures.put(RandomGeneratorFactory.class, Set.of(
166+
new MethodSignature("create"),
167+
new MethodSignature("create", long.class),
168+
new MethodSignature("create", byte[].class)
169+
));
170+
reflectionMethodSignatures.put(MethodHandleProxies.class, Set.of(
171+
new MethodSignature("asInterfaceInstance", Class.class, MethodHandle.class)
172+
));
155173

156-
reflectionMethodNames.put(ObjectOutputStream.class, Set.of("writeObject", "writeUnshared"));
157-
reflectionMethodNames.put(ObjectInputStream.class, Set.of(
158-
"resolveClass",
159-
"resolveProxyClass",
160-
"readObject",
161-
"readUnshared"));
162-
reflectionMethodNames.put(ObjectStreamClass.class, Set.of("lookup"));
174+
reflectionMethodSignatures.put(ObjectOutputStream.class, Set.of(
175+
new MethodSignature("writeObject", Object.class),
176+
new MethodSignature("writeUnshared", Object.class)
177+
));
178+
reflectionMethodSignatures.put(ObjectInputStream.class, Set.of(
179+
new MethodSignature("resolveClass", ObjectStreamClass.class),
180+
new MethodSignature("resolveProxyClass", String[].class),
181+
new MethodSignature("readObject"),
182+
new MethodSignature("readUnshared")
183+
));
184+
reflectionMethodSignatures.put(ObjectStreamClass.class, Set.of(
185+
new MethodSignature("lookup", Class.class)
186+
));
163187

164-
reflectionMethodNames.put(Proxy.class, Set.of("getProxyClass", "newProxyInstance"));
188+
reflectionMethodSignatures.put(Proxy.class, Set.of(
189+
new MethodSignature("getProxyClass", ClassLoader.class, Class[].class),
190+
new MethodSignature("newProxyInstance", ClassLoader.class, Class[].class, InvocationHandler.class)
191+
));
165192

166-
resourceMethodNames.put(ClassLoader.class, Set.of(
167-
"getResource",
168-
"getResources",
169-
"getSystemResource",
170-
"getSystemResources"));
171-
resourceMethodNames.put(BuiltinClassLoader.class, Set.of("findResource", "findResourceAsStream"));
172-
resourceMethodNames.put(Loader.class, Set.of("findResource"));
173-
resourceMethodNames.put(ResourceBundle.class, Set.of("getBundleImpl"));
174-
resourceMethodNames.put(Module.class, Set.of("getResourceAsStream"));
175-
resourceMethodNames.put(Class.class, Set.of("getResource", "getResourceAsStream"));
193+
resourceMethodSignatures.put(ClassLoader.class, Set.of(
194+
new MethodSignature("getResource", String.class),
195+
new MethodSignature("getResources", String.class),
196+
new MethodSignature("getSystemResource", String.class),
197+
new MethodSignature("getSystemResources", String.class)
198+
));
199+
resourceMethodSignatures.put(Module.class, Set.of(
200+
new MethodSignature("getResourceAsStream", String.class)
201+
));
202+
resourceMethodSignatures.put(Class.class, Set.of(
203+
new MethodSignature("getResource", String.class),
204+
new MethodSignature("getResourceAsStream", String.class)
205+
));
206+
resourceMethodSignatures.put(ResourceBundle.class, Set.of(
207+
new MethodSignature("getBundle", String.class),
208+
new MethodSignature("getBundle", String.class, ResourceBundle.Control.class),
209+
new MethodSignature("getBundle", String.class, Locale.class),
210+
new MethodSignature("getBundle", String.class, Module.class),
211+
new MethodSignature("getBundle", String.class, Locale.class, Module.class),
212+
new MethodSignature("getBundle", String.class, Locale.class, ResourceBundle.Control.class),
213+
new MethodSignature("getBundle", String.class, Locale.class, ClassLoader.class),
214+
new MethodSignature("getBundle", String.class, Locale.class, ClassLoader.class, ResourceBundle.Control.class)
215+
));
176216
}
177217

178218
public DynamicAccessDetectionPhase() {
@@ -185,11 +225,11 @@ protected void run(StructuredGraph graph, CoreProviders context) {
185225
for (MethodCallTargetNode callTarget : callTargetNodes) {
186226
AnalysisType callerClass = (AnalysisType) graph.method().getDeclaringClass();
187227
String sourceEntry = getSourceEntry(callerClass);
188-
MethodInfo methodInfo = getMethod(callTarget);
228+
MethodInfo methodInfo = getMethodInfo(callTarget);
189229

190230
if (methodInfo != null && sourceEntry != null) {
191231
DynamicAccessKind accessKind = methodInfo.accessKind();
192-
String methodName = methodInfo.name();
232+
String methodName = methodInfo.signature();
193233

194234
NodeSourcePosition nspToShow = callTarget.getNodeSourcePosition();
195235
if (nspToShow != null) {
@@ -207,24 +247,32 @@ protected void run(StructuredGraph graph, CoreProviders context) {
207247
}
208248

209249
/*
210-
* Returns the name and dynamic access kind (reflective or resource) of a
250+
* Returns the signature, parameter types and dynamic access kind (reflective or resource) of a
211251
* method if it exists in the predetermined set, based on its graph and MethodCallTargetNode;
212252
* otherwise, returns null.
213253
*/
214-
private static MethodInfo getMethod(MethodCallTargetNode callTarget) {
254+
private MethodInfo getMethodInfo(MethodCallTargetNode callTarget) {
215255
String methodName = callTarget.targetMethod().getName();
216256
Class<?> declaringClass = OriginalClassProvider.getJavaClass(callTarget.targetMethod().getDeclaringClass());
257+
List<Class<?>> paramList = new ArrayList<>();
258+
Signature signature = callTarget.targetMethod().getSignature();
259+
for (int i = 0; i < signature.getParameterCount(false); i++) {
260+
JavaType type = signature.getParameterType(i, callTarget.targetMethod().getDeclaringClass());
261+
paramList.add(OriginalClassProvider.getJavaClass(type));
262+
}
263+
Class<?>[] paramTypes = paramList.toArray(new Class<?>[0]);
264+
MethodSignature methodSignature = new MethodSignature(methodName, paramTypes);
217265

218-
if (reflectionMethodNames.containsKey(declaringClass) && reflectionMethodNames.get(declaringClass).contains(methodName)) {
219-
return new MethodInfo(DynamicAccessKind.Reflection, declaringClass.getName() + "#" + methodName);
220-
} else if (resourceMethodNames.containsKey(declaringClass) && resourceMethodNames.get(declaringClass).contains(methodName)) {
221-
return new MethodInfo(DynamicAccessKind.Resource, declaringClass.getName() + "#" + methodName);
266+
if (reflectionMethodSignatures.containsKey(declaringClass) && reflectionMethodSignatures.get(declaringClass).contains(methodSignature)) {
267+
return new MethodInfo(DynamicAccessKind.Reflection, declaringClass.getName() + "#" + methodSignature);
268+
} else if (resourceMethodSignatures.containsKey(declaringClass) && resourceMethodSignatures.get(declaringClass).contains(methodSignature)) {
269+
return new MethodInfo(DynamicAccessKind.Resource, declaringClass.getName() + "#" + methodSignature);
222270
}
223271
return null;
224272
}
225273

226274
/*
227-
* Returns the class path entry, module or package name of the caller class if it is included in the value
275+
* Returns the class path entry, module or package signature of the caller class if it is included in the value
228276
* specified by the option, otherwise returns null.
229277
*/
230278
private static String getSourceEntry(AnalysisType callerClass) {
@@ -249,7 +297,7 @@ private static String getSourceEntry(AnalysisType callerClass) {
249297
}
250298

251299
String moduleName = callerClass.getJavaClass().getModule().getName();
252-
if (sourceEntries.contains(moduleName)) {
300+
if (moduleName != null && sourceEntries.contains(moduleName)) {
253301
return moduleName;
254302
}
255303

@@ -262,4 +310,46 @@ private static String getSourceEntry(AnalysisType callerClass) {
262310
throw new RuntimeException(e);
263311
}
264312
}
313+
314+
private static class MethodSignature {
315+
private final String name;
316+
private final Class<?>[] paramTypes;
317+
318+
public MethodSignature(String name, Class<?>... paramTypes) {
319+
this.name = name;
320+
this.paramTypes = paramTypes;
321+
}
322+
323+
@Override
324+
public boolean equals(Object o) {
325+
if (this == o) return true;
326+
if (!(o instanceof MethodSignature that)) return false;
327+
return name.equals(that.name) && Arrays.equals(paramTypes, that.paramTypes);
328+
}
329+
330+
@Override
331+
public int hashCode() {
332+
return Objects.hash(name, Arrays.hashCode(paramTypes));
333+
}
334+
335+
@Override
336+
public String toString() {
337+
StringBuilder sb = new StringBuilder();
338+
sb.append(name).append("(");
339+
for (int i = 0; i < paramTypes.length; i++) {
340+
if (i > 0) sb.append(", ");
341+
Class<?> param = paramTypes[i];
342+
if (param.isArray()) {
343+
sb.append(param.getComponentType().getName()).append("[]");
344+
} else {
345+
sb.append(param.getName());
346+
}
347+
if (param.getTypeName().contains("?")) {
348+
sb.append("<?>");
349+
}
350+
}
351+
sb.append(")");
352+
return sb.toString();
353+
}
354+
}
265355
}

0 commit comments

Comments
 (0)