I'm writing a native Java agent using JVMTI that goes over all the methods of all the loaded classes. Unfortunately many classes seem not yet prepared and therefore GetClassMethods
returns JVMTI_ERROR_CLASS_NOT_PREPARED
. I am registering a ClassPrepare
event callback but that seem to be called only for very few classes. Simplified (minus all the error handling and deallocation) my code looks like this
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* jvm, char *options, void *reserved) {
jvmtiEnv *jvmti;
jint class_count;
jclass* classes;
jint method_count;
jmethodID* methods;
(*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_11);
(*jvmti)->GetLoadedClasses(jvmti, &class_count, &classes);
for (int i = 0; i < class_count; i++) {
jclass klass = classes[i];
// here a lot of time JVMTI_ERROR_CLASS_NOT_PREPARED is returned
jvmtiError err = (*jvmti)->GetClassMethods(jvmti, klass, &method_count, &methods);
}
The agent is attached dynamically to a running JVM using JCMD and the JVMTI.agent_load command. I did try to register a class prepare callback using:
jvmtiEventCallbacks callbacks;
(void)memset(&callbacks, 0, sizeof(callbacks));
callbacks.ClassPrepare = &callbackClassPrepare;
(*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint) sizeof(callbacks));
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, (jthread) NULL);
But this ended only being called for very few classes.
How can I get the JVM to prepare the loaded classes so that GetClassMethods
returns JVMTI_ERROR_NONE
?
So far I have only tested with JDK 17.0.1 with Shenandoah GC.