I am working on a research project which includes Hotspot profiler's feedback. Currently I am working on a JVMTI agent which should have following features:
- listen any compiled load event.
- Extract and analyse the complete class file which has hotspot method.
- Modify/Redefine the bytecodes of the class.
I have a lot of API functions available in JVMTI to get the information about the class file having the method which is being compiled by JIT. However, I want the complete class file of the method as described in java virtual machine specification. If it is not possible to get a whole class file, I would at least want a class file in following format:
typedef struct {
unsigned int magic;
unsigned short minor_version;
unsigned short major_version;
unsigned short constant_pool_count;
unsigned char *constant_pool;
unsigned short access_flags;
unsigned short this_class;
unsigned short super_class;
unsigned short interfaces_count;
unsigned char *interfaces;
unsigned short fields_count;
unsigned char *fields;
unsigned short methods_count;
unsigned char *methods;
unsigned short attributes_count;
unsigned char *attributes;
}ClassFile;
I have following code so far which serves the purpose partially:
void JNICALL compiled_method_load(jvmtiEnv *jvmti, jmethodID method, jint code_size, const void* code_addr, jint map_length, const jvmtiAddrLocationMap* map, const void* compile_info)
{
static ClassFile *clazz;
jvmtiError err;
jclass klass;
jint constant_pool_count_pointer;
jint constant_pool_byte_count_pointer;
jint local_entry_count_ptr;
jint minor, major;
jint modifier_ptr;
jvmtiLocalVariableEntry* table_ptr;
unsigned char* constant_pool_bytes_ptr;
char* name = NULL;
char* signature = NULL;
char* generic_ptr = NULL;
unsigned char* bytecodes_ptr = NULL;
err = (*jvmti)->RawMonitorEnter(jvmti,lock);
check_jvmti_error(jvmti, err, "raw monitor enter");
clazz->magic = 0xCAFEBABE;
err = (*jvmti)->GetMethodDeclaringClass(jvmti,method, &klass);
check_jvmti_error(jvmti, err, "Get Declaring Class");
err = (*jvmti)->GetClassVersionNumbers(jvmti, klass, &minor, &major);
check_jvmti_error(jvmti, err, "Get Class Version Number");
clazz->minor_version = (u2_int)minor;
clazz->major_version = (u2_int)major;
err = (*jvmti)->GetConstantPool(jvmti, klass, &constant_pool_count_pointer,
&constant_pool_byte_count_pointer, &constant_pool_bytes_ptr);
check_jvmti_error(jvmti, err, "Get Constant Pool");
clazz->constant_pool_count = constant_pool_count_pointer;
clazz->constant_pool = constant_pool_bytes_ptr;
err = (*jvmti)->GetClassModifiers(jvmti,klass, &modifier_ptr);
check_jvmti_error(jvmti, err, "Get Access Flags");
clazz->access_flags = (u2_int)modifier_ptr;
err = (*jvmti)->GetBytecodes(jvmti,method, &code_size, &bytecodes_ptr);
check_jvmti_error(jvmti, err, "Get Bytecodes");
err = (*jvmti)->GetLocalVariableTable(jvmti,method, &local_entry_count_ptr, &table_ptr);
check_jvmti_error(jvmti, err, "Get Local Variable table");
if (constant_pool_bytes_ptr != NULL) {
err = (*jvmti)->Deallocate(jvmti,(unsigned char*)constant_pool_bytes_ptr);
check_jvmti_error(jvmti, err, "deallocate bytecodes pointer");
}
if (bytecodes_ptr != NULL) {
err = (*jvmti)->Deallocate(jvmti,(unsigned char*)bytecodes_ptr);
check_jvmti_error(jvmti, err, "deallocate bytecodes pointer");
}
if (name != NULL) {
err = (*jvmti)->Deallocate(jvmti,(unsigned char*)name);
check_jvmti_error(jvmti, err, "deallocate name");
}
if (signature != NULL) {
err = (*jvmti)->Deallocate(jvmti,(unsigned char*)signature);
check_jvmti_error(jvmti, err, "deallocate signature");
}
if (generic_ptr != NULL) {
err = (*jvmti)->Deallocate(jvmti,(unsigned char*)generic_ptr);
check_jvmti_error(jvmti, err, "deallocate generic_ptr");
}
err = (*jvmti)->RawMonitorExit(jvmti,lock);
}
My questions are:
- Is it possible to get complete class file through an agent?
- If not, how can I fill the
ClassFile
structure usingJVMTI
orJNI
API? - Any other strategy to achieve my objective?
Limitations:
- I have to examine and manipulate bytecodes during runtime a long time after class loading. So AFAIK java agents using libraries like
ASM
andJAVASSIST
wouldn't be of any help.
Any help would be highly appreciated.