/* Lookup or create a new TraceInfo */ static TraceInfo * lookupOrEnter(jvmtiEnv *jvmti, Trace *trace, TraceFlavor flavor) { TraceInfo *tinfo; jlong hashCode; /* Calculate hash code (outside critical section to lessen contention) */ hashCode = hashTrace(trace); /* Do a lookup in the hash table */ enterCriticalSection(jvmti); { TraceInfo *prev; int hashIndex; /* Start with first item in hash buck chain */ prev = NULL; hashIndex = (int)(hashCode & HASH_INDEX_MASK); tinfo = gdata->hashBuckets[hashIndex]; while ( tinfo != NULL ) { if ( tinfo->hashCode == hashCode && memcmp(trace, &(tinfo->trace), sizeof(Trace))==0 ) { /* We found one that matches, move to head of bucket chain */ if ( prev != NULL ) { /* Remove from list and add to head of list */ prev->next = tinfo->next; tinfo->next = gdata->hashBuckets[hashIndex]; gdata->hashBuckets[hashIndex] = tinfo; } /* Break out */ break; } prev = tinfo; tinfo = tinfo->next; } /* If we didn't find anything we need to enter a new entry */ if ( tinfo == NULL ) { /* Create new hash table element */ tinfo = newTraceInfo(trace, hashCode, flavor); } /* Update stats */ (void)updateStats(tinfo); } exitCriticalSection(jvmti); return tinfo; }
/* Agent_OnLoad: This is called immediately after the shared library is * loaded. This is the first code executed. */ JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { static GlobalAgentData data; jvmtiEnv *jvmti; jvmtiError error; jint res; TraceFlavor flavor; jvmtiCapabilities capabilities; jvmtiEventCallbacks callbacks; static Trace empty; /* Setup initial global agent data area * Use of static/extern data should be handled carefully here. * We need to make sure that we are able to cleanup after ourselves * so anything allocated in this library needs to be freed in * the Agent_OnUnload() function. */ (void)memset((void*)&data, 0, sizeof(data)); gdata = &data; /* First thing we need to do is get the jvmtiEnv* or JVMTI environment */ res = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1); if (res != JNI_OK) { /* This means that the VM was unable to obtain this version of the * JVMTI interface, this is a fatal error. */ fatal_error("ERROR: Unable to access JVMTI Version 1 (0x%x)," " is your JDK a 5.0 or newer version?" " JNIEnv's GetEnv() returned %d\n", JVMTI_VERSION_1, res); } /* Here we save the jvmtiEnv* for Agent_OnUnload(). */ gdata->jvmti = jvmti; /* Parse any options supplied on java command line */ parse_agent_options(options); /* Immediately after getting the jvmtiEnv* we need to ask for the * capabilities this agent will need. */ (void)memset(&capabilities,0, sizeof(capabilities)); capabilities.can_generate_all_class_hook_events = 1; capabilities.can_tag_objects = 1; capabilities.can_generate_object_free_events = 1; capabilities.can_get_source_file_name = 1; capabilities.can_get_line_numbers = 1; capabilities.can_generate_vm_object_alloc_events = 1; error = (*jvmti)->AddCapabilities(jvmti, &capabilities); check_jvmti_error(jvmti, error, "Unable to get necessary JVMTI capabilities."); /* Next we need to provide the pointers to the callback functions to * to this jvmtiEnv* */ (void)memset(&callbacks,0, sizeof(callbacks)); /* JVMTI_EVENT_VM_START */ callbacks.VMStart = &cbVMStart; /* JVMTI_EVENT_VM_INIT */ callbacks.VMInit = &cbVMInit; /* JVMTI_EVENT_VM_DEATH */ callbacks.VMDeath = &cbVMDeath; /* JVMTI_EVENT_OBJECT_FREE */ callbacks.ObjectFree = &cbObjectFree; /* JVMTI_EVENT_VM_OBJECT_ALLOC */ callbacks.VMObjectAlloc = &cbVMObjectAlloc; /* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */ callbacks.ClassFileLoadHook = &cbClassFileLoadHook; error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks)); check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks"); /* At first the only initial events we are interested in are VM * initialization, VM death, and Class File Loads. * Once the VM is initialized we will request more events. */ error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); /* Here we create a raw monitor for our use in this agent to * protect critical sections of code. */ error = (*jvmti)->CreateRawMonitor(jvmti, "agent data", &(gdata->lock)); check_jvmti_error(jvmti, error, "Cannot create raw monitor"); /* Create the TraceInfo for various flavors of empty traces */ for ( flavor = TRACE_FIRST ; flavor <= TRACE_LAST ; flavor++ ) { gdata->emptyTrace[flavor] = newTraceInfo(&empty, hashTrace(&empty), flavor); } /* Add jar file to boot classpath */ add_demo_jar_to_bootclasspath(jvmti, "heapTracker"); /* We return JNI_OK to signify success */ return JNI_OK; }