4949import static com .oracle .svm .jvmtiagentbase .jvmti .JvmtiEvent .JVMTI_EVENT_NATIVE_METHOD_BIND ;
5050import static org .graalvm .word .WordFactory .nullPointer ;
5151
52+ import java .lang .reflect .Field ;
5253import java .nio .ByteBuffer ;
5354import java .nio .ByteOrder ;
5455import java .util .ArrayList ;
8081import com .oracle .svm .agent .stackaccess .EagerlyLoadedJavaStackAccess ;
8182import com .oracle .svm .agent .stackaccess .InterceptedState ;
8283import com .oracle .svm .agent .tracing .core .Tracer ;
84+ import com .oracle .svm .configure .ClassNameSupport ;
8385import com .oracle .svm .configure .LambdaConfigurationTypeDescriptor ;
8486import com .oracle .svm .configure .NamedConfigurationTypeDescriptor ;
8587import com .oracle .svm .configure .ProxyConfigurationTypeDescriptor ;
@@ -263,8 +265,17 @@ static Object getTypeDescriptor(JNIEnvironment env, JNIObjectHandle clazz) {
263265 }
264266
265267 private static boolean forName (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
266- JNIObjectHandle callerClass = state .getDirectCallerClass ();
267268 JNIObjectHandle name = getObjectArgument (thread , 0 );
269+ return handleForName (jni , bp , state , name );
270+ }
271+
272+ private static boolean forNameWithModule (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
273+ JNIObjectHandle name = getObjectArgument (thread , 1 );
274+ return handleForName (jni , bp , state , name );
275+ }
276+
277+ private static boolean handleForName (JNIEnvironment jni , Breakpoint bp , InterceptedState state , JNIObjectHandle name ) {
278+ JNIObjectHandle callerClass = state .getDirectCallerClass ();
268279 String className = fromJniString (jni , name );
269280 if (className == null ) {
270281 return true ; /* No point in tracing this. */
@@ -273,6 +284,14 @@ private static boolean forName(JNIEnvironment jni, JNIObjectHandle thread, Break
273284 return true ;
274285 }
275286
287+ private static boolean arrayType (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
288+ JNIObjectHandle callerClass = state .getDirectCallerClass ();
289+ JNIObjectHandle componentType = getReceiver (thread );
290+ String arrayTypeName = ClassNameSupport .getArrayReflectionName (getClassNameOrNull (jni , componentType ));
291+ traceReflectBreakpoint (jni , bp .clazz , nullHandle (), callerClass , "forName" , null , state .getFullStackTraceOrNull (), arrayTypeName );
292+ return true ;
293+ }
294+
276295 private static boolean getFields (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
277296 return handleGetFields (jni , thread , bp , state );
278297 }
@@ -543,6 +562,34 @@ private static boolean getEnclosingMethod(JNIEnvironment jni, JNIObjectHandle th
543562 return true ;
544563 }
545564
565+ private static boolean accessField (JNIEnvironment jni , JNIObjectHandle thread , @ SuppressWarnings ("unused" ) Breakpoint bp , InterceptedState state ) {
566+ JNIObjectHandle field = getReceiver (thread );
567+ return accessFieldInternal (jni , state , field );
568+ }
569+
570+ private static boolean accessFieldUnsafe (JNIEnvironment jni , JNIObjectHandle thread , @ SuppressWarnings ("unused" ) Breakpoint bp , InterceptedState state ) {
571+ JNIObjectHandle field = getObjectArgument (thread , 1 );
572+ return accessFieldInternal (jni , state , field );
573+ }
574+
575+ private static boolean accessFieldInternal (JNIEnvironment jni , InterceptedState state , JNIObjectHandle field ) {
576+ JNIObjectHandle callerClass = state .getDirectCallerClass ();
577+
578+ JNIObjectHandle declaring = Support .callObjectMethod (jni , field , agent .handles ().javaLangReflectMemberGetDeclaringClass );
579+ if (clearException (jni )) {
580+ declaring = nullHandle ();
581+ }
582+
583+ JNIObjectHandle nameHandle = Support .callObjectMethod (jni , field , agent .handles ().javaLangReflectMemberGetName );
584+ if (clearException (jni )) {
585+ nameHandle = nullHandle ();
586+ }
587+ String name = fromJniString (jni , nameHandle );
588+
589+ traceReflectBreakpoint (jni , declaring , declaring , callerClass , "accessField" , declaring .notEqual (nullHandle ()), state .getFullStackTraceOrNull (), name );
590+ return true ;
591+ }
592+
546593 private static boolean invokeMethod (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
547594 return handleInvokeMethod (jni , thread , bp , state , true );
548595 }
@@ -582,6 +629,27 @@ private static boolean handleInvokeMethod(JNIEnvironment jni, JNIObjectHandle th
582629 JNIObjectHandle clazz = getObjectArgument (thread , 1 );
583630 traceReflectBreakpoint (jni , clazz , nullHandle (), callerClass , "newInstance" , clazz .notEqual (nullHandle ()), state .getFullStackTraceOrNull ());
584631 }
632+
633+ /*
634+ * Calling Field.get/set and associated methods through Method.invoke should register the
635+ * field for reflective access
636+ */
637+ if (isInvoke && isFieldAccess (jni , declaring , name )) {
638+ JNIObjectHandle field = getObjectArgument (thread , 1 );
639+
640+ JNIObjectHandle clazz = Support .callObjectMethod (jni , field , agent .handles ().javaLangReflectMemberGetDeclaringClass );
641+ if (clearException (jni )) {
642+ clazz = nullHandle ();
643+ }
644+
645+ JNIObjectHandle fieldNameHandle = Support .callObjectMethod (jni , field , agent .handles ().javaLangReflectMemberGetName );
646+ if (clearException (jni )) {
647+ clazz = nullHandle ();
648+ }
649+ String fieldName = fromJniString (jni , fieldNameHandle );
650+
651+ traceReflectBreakpoint (jni , clazz , nullHandle (), callerClass , "accessField" , clazz .notEqual (nullHandle ()), state .getFullStackTraceOrNull (), fieldName );
652+ }
585653 return true ;
586654 }
587655
@@ -597,6 +665,24 @@ private static boolean isClassNewInstance(JNIEnvironment jni, JNIObjectHandle de
597665 return "java.lang.Class" .equals (className );
598666 }
599667
668+ /**
669+ * A call is a field access iff it is a call to a method from {@link Field} whose name starts
670+ * with "get" or "set".
671+ */
672+ private static boolean isFieldAccess (JNIEnvironment jni , JNIObjectHandle declaring , String name ) {
673+ if (declaring .equal (nullHandle ()) || name == null || (!name .startsWith ("get" ) && !name .startsWith ("set" ))) {
674+ return false ;
675+ }
676+
677+ JNIObjectHandle classNameHandle = Support .callObjectMethod (jni , declaring , agent .handles ().javaLangClassGetName );
678+ if (clearException (jni )) {
679+ classNameHandle = nullHandle ();
680+ }
681+ String className = fromJniString (jni , classNameHandle );
682+
683+ return Field .class .getName ().equals (className );
684+ }
685+
600686 private static boolean invokeConstructor (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
601687 return handleInvokeConstructor (jni , bp , state , getReceiver (thread ));
602688 }
@@ -1650,6 +1736,7 @@ private interface BreakpointHandler {
16501736 private static final BreakpointSpecification [] BREAKPOINT_SPECIFICATIONS = {
16511737 brk ("java/lang/Class" , "forName" , "(Ljava/lang/String;)Ljava/lang/Class;" , BreakpointInterceptor ::forName ),
16521738 brk ("java/lang/Class" , "forName" , "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;" , BreakpointInterceptor ::forName ),
1739+ brk ("java/lang/Class" , "forName" , "(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;" , BreakpointInterceptor ::forNameWithModule ),
16531740
16541741 brk ("java/lang/Class" , "getFields" , "()[Ljava/lang/reflect/Field;" , BreakpointInterceptor ::getFields ),
16551742 brk ("java/lang/Class" , "getClasses" , "()[Ljava/lang/Class;" , BreakpointInterceptor ::getClasses ),
@@ -1673,6 +1760,7 @@ private interface BreakpointHandler {
16731760 brk ("java/lang/Class" , "getDeclaredConstructor" , "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;" , BreakpointInterceptor ::getConstructor ),
16741761
16751762 brk ("java/lang/Class" , "newInstance" , "()Ljava/lang/Object;" , BreakpointInterceptor ::newInstance ),
1763+ brk ("java/lang/Class" , "arrayType" , "()Ljava/lang/Class;" , BreakpointInterceptor ::arrayType ),
16761764 brk ("java/lang/reflect/Array" , "newInstance" , "(Ljava/lang/Class;I)Ljava/lang/Object;" , BreakpointInterceptor ::newArrayInstance ),
16771765 brk ("java/lang/reflect/Array" , "newInstance" , "(Ljava/lang/Class;[I)Ljava/lang/Object;" , BreakpointInterceptor ::newArrayInstanceMulti ),
16781766
@@ -1712,6 +1800,7 @@ private interface BreakpointHandler {
17121800 optionalBrk ("jdk/internal/misc/Unsafe" , "objectFieldOffset" , "(Ljava/lang/Class;Ljava/lang/String;)J" , BreakpointInterceptor ::objectFieldOffsetByName ),
17131801
17141802 brk ("sun/misc/Unsafe" , "allocateInstance" , "(Ljava/lang/Class;)Ljava/lang/Object;" , BreakpointInterceptor ::allocateInstance ),
1803+ brk ("sun/misc/Unsafe" , "objectFieldOffset" , "(Ljava/lang/reflect/Field;)J" , BreakpointInterceptor ::accessFieldUnsafe ),
17151804
17161805 optionalBrk ("java/lang/invoke/MethodHandles$Lookup" , "findStatic" ,
17171806 "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;" ,
@@ -1762,6 +1851,9 @@ private interface BreakpointHandler {
17621851 optionalBrk ("java/lang/invoke/MethodHandles$Lookup" , "unreflectSetter" ,
17631852 "(Ljava/lang/reflect/Field;)Ljava/lang/invoke/MethodHandle;" ,
17641853 BreakpointInterceptor ::unreflectField ),
1854+ optionalBrk ("java/lang/invoke/MethodHandles$Lookup" , "unreflectVarHandle" ,
1855+ "(Ljava/lang/reflect/Field;)Ljava/lang/invoke/VarHandle;" ,
1856+ BreakpointInterceptor ::unreflectField ),
17651857 optionalBrk ("java/lang/invoke/MethodHandleProxies" , "asInterfaceInstance" ,
17661858 "(Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;" ,
17671859 BreakpointInterceptor ::asInterfaceInstance ),
@@ -1810,6 +1902,24 @@ private static boolean allocateInstance(JNIEnvironment jni, JNIObjectHandle thre
18101902 brk ("java/lang/reflect/Method" , "invoke" , "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" , BreakpointInterceptor ::invokeMethod ),
18111903 brk ("sun/reflect/misc/MethodUtil" , "invoke" , "(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" , BreakpointInterceptor ::invokeMethod ),
18121904 brk ("java/lang/reflect/Constructor" , "newInstance" , "([Ljava/lang/Object;)Ljava/lang/Object;" , BreakpointInterceptor ::invokeConstructor ),
1905+ brk ("java/lang/reflect/Field" , "get" , "(Ljava/lang/Object;)Ljava/lang/Object;" , BreakpointInterceptor ::accessField ),
1906+ brk ("java/lang/reflect/Field" , "set" , "(Ljava/lang/Object;Ljava/lang/Object;)V" , BreakpointInterceptor ::accessField ),
1907+ brk ("java/lang/reflect/Field" , "getBoolean" , "(Ljava/lang/Object;)Z" , BreakpointInterceptor ::accessField ),
1908+ brk ("java/lang/reflect/Field" , "setBoolean" , "(Ljava/lang/Object;Z)V" , BreakpointInterceptor ::accessField ),
1909+ brk ("java/lang/reflect/Field" , "getByte" , "(Ljava/lang/Object;)B" , BreakpointInterceptor ::accessField ),
1910+ brk ("java/lang/reflect/Field" , "setByte" , "(Ljava/lang/Object;B)V" , BreakpointInterceptor ::accessField ),
1911+ brk ("java/lang/reflect/Field" , "getShort" , "(Ljava/lang/Object;)S" , BreakpointInterceptor ::accessField ),
1912+ brk ("java/lang/reflect/Field" , "setShort" , "(Ljava/lang/Object;S)V" , BreakpointInterceptor ::accessField ),
1913+ brk ("java/lang/reflect/Field" , "getChar" , "(Ljava/lang/Object;)C" , BreakpointInterceptor ::accessField ),
1914+ brk ("java/lang/reflect/Field" , "setChar" , "(Ljava/lang/Object;C)V" , BreakpointInterceptor ::accessField ),
1915+ brk ("java/lang/reflect/Field" , "getInt" , "(Ljava/lang/Object;)I" , BreakpointInterceptor ::accessField ),
1916+ brk ("java/lang/reflect/Field" , "setInt" , "(Ljava/lang/Object;I)V" , BreakpointInterceptor ::accessField ),
1917+ brk ("java/lang/reflect/Field" , "getLong" , "(Ljava/lang/Object;)J" , BreakpointInterceptor ::accessField ),
1918+ brk ("java/lang/reflect/Field" , "setLong" , "(Ljava/lang/Object;J)V" , BreakpointInterceptor ::accessField ),
1919+ brk ("java/lang/reflect/Field" , "getFloat" , "(Ljava/lang/Object;)F" , BreakpointInterceptor ::accessField ),
1920+ brk ("java/lang/reflect/Field" , "setFloat" , "(Ljava/lang/Object;F)V" , BreakpointInterceptor ::accessField ),
1921+ brk ("java/lang/reflect/Field" , "getDouble" , "(Ljava/lang/Object;)D" , BreakpointInterceptor ::accessField ),
1922+ brk ("java/lang/reflect/Field" , "setDouble" , "(Ljava/lang/Object;D)V" , BreakpointInterceptor ::accessField ),
18131923 };
18141924
18151925 private static final BreakpointSpecification [] CLASS_PREDEFINITION_BREAKPOINT_SPECIFICATIONS = {
0 commit comments