Skip to content

Commit 654c0cd

Browse files
committed
WIP
1 parent be01334 commit 654c0cd

File tree

37 files changed

+1705
-156
lines changed

37 files changed

+1705
-156
lines changed

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ReflectionRegistry.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,8 @@ public interface ReflectionRegistry {
5050

5151
void register(boolean finalIsWritable, Field... fields);
5252

53+
@SuppressWarnings("unused")
54+
default void registerAsQueried(Executable... methods) {
55+
// TODO unimplemented/shouldNotReachHere?
56+
}
5357
}

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ final class BreakpointInterceptor {
136136
/** Enables experimental support for class definitions via {@code ClassLoader.defineClass}. */
137137
private static boolean experimentalClassDefineSupport = false;
138138

139+
/** Enables tracking of reflection queries for fine-tuned configuration. */
140+
private static boolean trackReflectionMetadata = false;
141+
139142
/**
140143
* Locations in methods where explicit calls to {@code ClassLoader.loadClass} have been found.
141144
*/
@@ -367,6 +370,52 @@ private static boolean getEnclosingMethod(JNIEnvironment jni, Breakpoint bp, Int
367370
return true;
368371
}
369372

373+
private static boolean invokeMethod(JNIEnvironment jni, Breakpoint bp, InterceptedState state) {
374+
JNIObjectHandle callerClass = state.getDirectCallerClass();
375+
JNIObjectHandle self = getObjectArgument(0);
376+
377+
JNIObjectHandle declaring = Support.callObjectMethod(jni, self, agent.handles().javaLangReflectMemberGetDeclaringClass);
378+
if (clearException(jni)) {
379+
declaring = nullHandle();
380+
}
381+
382+
JNIObjectHandle nameHandle = Support.callObjectMethod(jni, self, agent.handles().javaLangReflectMemberGetName);
383+
if (clearException(jni)) {
384+
nameHandle = nullHandle();
385+
}
386+
String name = fromJniString(jni, nameHandle);
387+
388+
JNIObjectHandle paramTypesHandle = Support.callObjectMethod(jni, self, agent.handles().javaLangReflectExecutableGetParameterTypes);
389+
if (clearException(jni)) {
390+
paramTypesHandle = nullHandle();
391+
}
392+
Object paramTypes = getClassArrayNames(jni, paramTypesHandle);
393+
394+
traceBreakpoint(jni, declaring, declaring, callerClass, bp.specification.methodName, self.notEqual(nullHandle()), state.getFullStackTraceOrNull(), name, paramTypes);
395+
return true;
396+
}
397+
398+
private static boolean invokeConstructor(JNIEnvironment jni, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
399+
JNIObjectHandle callerClass = state.getDirectCallerClass();
400+
JNIObjectHandle self = getObjectArgument(0);
401+
402+
JNIObjectHandle declaring = Support.callObjectMethod(jni, self, agent.handles().javaLangReflectMemberGetDeclaringClass);
403+
if (clearException(jni)) {
404+
declaring = nullHandle();
405+
}
406+
407+
String name = "<init>";
408+
409+
JNIObjectHandle paramTypesHandle = Support.callObjectMethod(jni, self, agent.handles().javaLangReflectExecutableGetParameterTypes);
410+
if (clearException(jni)) {
411+
paramTypesHandle = nullHandle();
412+
}
413+
Object paramTypes = getClassArrayNames(jni, paramTypesHandle);
414+
415+
traceBreakpoint(jni, declaring, declaring, callerClass, "invoke", self.notEqual(nullHandle()), state.getFullStackTraceOrNull(), name, paramTypes);
416+
return true;
417+
}
418+
370419
private static boolean newInstance(JNIEnvironment jni, Breakpoint bp, InterceptedState state) {
371420
JNIObjectHandle callerClass = state.getDirectCallerClass();
372421
JNIMethodId result = nullPointer();
@@ -1068,12 +1117,13 @@ private static void onClassFileLoadHook(@SuppressWarnings("unused") JvmtiEnv jvm
10681117

10691118
public static void onLoad(JvmtiEnv jvmti, JvmtiEventCallbacks callbacks, Tracer writer, NativeImageAgent nativeImageTracingAgent,
10701119
Supplier<InterceptedState> currentThreadJavaStackAccessSupplier,
1071-
boolean exptlClassLoaderSupport, boolean exptlClassDefineSupport) {
1120+
boolean exptlClassLoaderSupport, boolean exptlClassDefineSupport, boolean trackReflectionData) {
10721121
BreakpointInterceptor.tracer = writer;
10731122
BreakpointInterceptor.agent = nativeImageTracingAgent;
10741123
BreakpointInterceptor.interceptedStateSupplier = currentThreadJavaStackAccessSupplier;
10751124
BreakpointInterceptor.experimentalClassLoaderSupport = exptlClassLoaderSupport;
10761125
BreakpointInterceptor.experimentalClassDefineSupport = exptlClassDefineSupport;
1126+
BreakpointInterceptor.trackReflectionMetadata = trackReflectionData;
10771127

10781128
JvmtiCapabilities capabilities = UnmanagedMemory.calloc(SizeOf.get(JvmtiCapabilities.class));
10791129
check(jvmti.getFunctions().GetCapabilities().invoke(jvmti, capabilities));
@@ -1122,7 +1172,13 @@ public static void onVMInit(JvmtiEnv jvmti, JNIEnvironment jni) {
11221172

11231173
JNIObjectHandle lastClass = nullHandle();
11241174
String lastClassName = null;
1125-
for (BreakpointSpecification br : BREAKPOINT_SPECIFICATIONS) {
1175+
BreakpointSpecification[] breakpointSpecifications = BREAKPOINT_SPECIFICATIONS;
1176+
if (trackReflectionMetadata) {
1177+
breakpointSpecifications = new BreakpointSpecification[BREAKPOINT_SPECIFICATIONS.length + REFLECTION_QUERIES_BREAKPOINT_SPECIFICATIONS.length];
1178+
System.arraycopy(BREAKPOINT_SPECIFICATIONS, 0, breakpointSpecifications, 0, BREAKPOINT_SPECIFICATIONS.length);
1179+
System.arraycopy(REFLECTION_QUERIES_BREAKPOINT_SPECIFICATIONS, 0, breakpointSpecifications, BREAKPOINT_SPECIFICATIONS.length, REFLECTION_QUERIES_BREAKPOINT_SPECIFICATIONS.length);
1180+
}
1181+
for (BreakpointSpecification br : breakpointSpecifications) {
11261182
JNIObjectHandle clazz = nullHandle();
11271183
if (lastClassName != null && lastClassName.equals(br.className)) {
11281184
clazz = lastClass;
@@ -1245,24 +1301,18 @@ private interface BreakpointHandler {
12451301
brk("java/lang/Class", "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", BreakpointInterceptor::forName),
12461302

12471303
brk("java/lang/Class", "getFields", "()[Ljava/lang/reflect/Field;", BreakpointInterceptor::getFields),
1248-
brk("java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;", BreakpointInterceptor::getMethods),
1249-
brk("java/lang/Class", "getConstructors", "()[Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getConstructors),
12501304
brk("java/lang/Class", "getClasses", "()[Ljava/lang/Class;", BreakpointInterceptor::getClasses),
12511305
brk("java/lang/Class", "getDeclaredFields", "()[Ljava/lang/reflect/Field;", BreakpointInterceptor::getDeclaredFields),
1252-
brk("java/lang/Class", "getDeclaredMethods", "()[Ljava/lang/reflect/Method;", BreakpointInterceptor::getDeclaredMethods),
1253-
brk("java/lang/Class", "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getDeclaredConstructors),
12541306
brk("java/lang/Class", "getDeclaredClasses", "()[Ljava/lang/Class;", BreakpointInterceptor::getDeclaredClasses),
12551307

12561308
brk("java/lang/Class", "getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", BreakpointInterceptor::getField),
12571309
brk("java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", BreakpointInterceptor::getDeclaredField),
1258-
brk("java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", BreakpointInterceptor::getMethod),
1259-
brk("java/lang/Class", "getConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getConstructor),
1260-
brk("java/lang/Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", BreakpointInterceptor::getDeclaredMethod),
1261-
brk("java/lang/Class", "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getConstructor),
12621310

12631311
brk("java/lang/Class", "getEnclosingMethod", "()Ljava/lang/reflect/Method;", BreakpointInterceptor::getEnclosingMethod),
12641312
brk("java/lang/Class", "getEnclosingConstructor", "()Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getEnclosingMethod),
12651313

1314+
brk("java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", BreakpointInterceptor::invokeMethod),
1315+
brk("java/lang/reflect/Constructor", "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;", BreakpointInterceptor::invokeConstructor),
12661316
brk("java/lang/Class", "newInstance", "()Ljava/lang/Object;", BreakpointInterceptor::newInstance),
12671317
brk("java/lang/reflect/Array", "newInstance", "(Ljava/lang/Class;I)Ljava/lang/Object;", BreakpointInterceptor::newArrayInstance),
12681318
brk("java/lang/reflect/Array", "newInstance", "(Ljava/lang/Class;[I)Ljava/lang/Object;", BreakpointInterceptor::newArrayInstanceMulti),
@@ -1353,6 +1403,18 @@ private interface BreakpointHandler {
13531403
private static final BreakpointSpecification CLASSLOADER_LOAD_CLASS_BREAKPOINT_SPECIFICATION = optionalBrk("java/lang/ClassLoader", "loadClass",
13541404
"(Ljava/lang/String;)Ljava/lang/Class;", BreakpointInterceptor::loadClass);
13551405

1406+
private static final BreakpointSpecification[] REFLECTION_QUERIES_BREAKPOINT_SPECIFICATIONS = {
1407+
brk("java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;", BreakpointInterceptor::getMethods),
1408+
brk("java/lang/Class", "getConstructors", "()[Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getConstructors),
1409+
brk("java/lang/Class", "getDeclaredMethods", "()[Ljava/lang/reflect/Method;", BreakpointInterceptor::getDeclaredMethods),
1410+
brk("java/lang/Class", "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getDeclaredConstructors),
1411+
1412+
brk("java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", BreakpointInterceptor::getMethod),
1413+
brk("java/lang/Class", "getConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getConstructor),
1414+
brk("java/lang/Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", BreakpointInterceptor::getDeclaredMethod),
1415+
brk("java/lang/Class", "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getConstructor),
1416+
};
1417+
13561418
private static BreakpointSpecification brk(String className, String methodName, String signature, BreakpointHandler handler) {
13571419
return new BreakpointSpecification(className, methodName, signature, handler, false);
13581420
}

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
121121
boolean configurationWithOrigins = false;
122122
int configWritePeriod = -1; // in seconds
123123
int configWritePeriodInitialDelay = 1; // in seconds
124+
boolean trackReflectionMetadata = false;
124125

125126
String[] tokens = !options.isEmpty() ? options.split(",") : new String[0];
126127
for (String token : tokens) {
@@ -189,6 +190,8 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
189190
build = Boolean.parseBoolean(getTokenValue(token));
190191
} else if (token.equals("experimental-configuration-with-origins")) {
191192
configurationWithOrigins = true;
193+
} else if (token.equals("track-reflection-metadata")) {
194+
trackReflectionMetadata = true;
192195
} else {
193196
return usage(1, "unknown option: '" + token + "'.");
194197
}
@@ -306,7 +309,8 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
306309
}
307310

308311
try {
309-
BreakpointInterceptor.onLoad(jvmti, callbacks, tracer, this, interceptedStateSupplier, experimentalClassLoaderSupport, experimentalClassDefineSupport);
312+
BreakpointInterceptor.onLoad(jvmti, callbacks, tracer, this, interceptedStateSupplier,
313+
experimentalClassLoaderSupport, experimentalClassDefineSupport, trackReflectionMetadata);
310314
} catch (Throwable t) {
311315
return error(3, t.toString());
312316
}

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgentJNIHandleSet.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class NativeImageAgentJNIHandleSet extends JNIHandleSet {
4242

4343
final JNIMethodId javaLangReflectMemberGetName;
4444
final JNIMethodId javaLangReflectMemberGetDeclaringClass;
45+
final JNIMethodId javaLangReflectExecutableGetParameterTypes;
4546

4647
final JNIMethodId javaUtilEnumerationHasMoreElements;
4748

@@ -78,6 +79,8 @@ public class NativeImageAgentJNIHandleSet extends JNIHandleSet {
7879
JNIObjectHandle javaLangReflectMember = findClass(env, "java/lang/reflect/Member");
7980
javaLangReflectMemberGetName = getMethodId(env, javaLangReflectMember, "getName", "()Ljava/lang/String;", false);
8081
javaLangReflectMemberGetDeclaringClass = getMethodId(env, javaLangReflectMember, "getDeclaringClass", "()Ljava/lang/Class;", false);
82+
JNIObjectHandle javaLangReflectExecutable = findClass(env, "java/lang/reflect/Executable");
83+
javaLangReflectExecutableGetParameterTypes = getMethodId(env, javaLangReflectExecutable, "getParameterTypes", "()[Ljava/lang/Class;", false);
8184

8285
JNIObjectHandle javaUtilEnumeration = findClass(env, "java/util/Enumeration");
8386
javaUtilEnumerationHasMoreElements = getMethodId(env, javaUtilEnumeration, "hasMoreElements", "()Z", false);

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/predicatedconfig/MethodInfo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
import java.util.Objects;
2828

29-
import com.oracle.svm.configure.config.SignatureUtil;
29+
import com.oracle.svm.core.reflect.SignatureUtil;
3030

3131
public class MethodInfo {
3232

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationMethod.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.oracle.svm.configure.json.JsonPrintable;
3232
import com.oracle.svm.configure.json.JsonWriter;
3333

34+
import com.oracle.svm.core.reflect.SignatureUtil;
3435
import jdk.vm.ci.meta.MetaUtil;
3536

3637
public class ConfigurationMethod implements JsonPrintable {

0 commit comments

Comments
 (0)