void site_heapdump(JNIEnv *env) { rawMonitorEnter(gdata->data_access_lock); { jvmtiHeapCallbacks heapCallbacks; /* Remove class dumped status, all classes must be dumped */ class_all_status_remove(CLASS_DUMPED); /* Clear in_heap_dump flag */ tls_clear_in_heap_dump(); /* Dump the last thread traces and get the lists back we need */ tls_dump_traces(env); /* Write header for heap dump */ io_heap_header(gdata->total_live_instances, gdata->total_live_bytes); /* Setup a clean reference table */ reference_init(); /* Walk over all reachable objects and dump out roots */ gdata->gref_serial_number_counter = gdata->gref_serial_number_start; /* Issue thread object for fake non-existent unknown thread * just in case someone refers to it. Real threads are handled * during iterate over reachable objects. */ io_heap_root_thread_object(0, gdata->unknown_thread_serial_num, trace_get_serial_number(gdata->system_trace_index)); /* Iterate over heap and get the real stuff */ (void)memset(&heapCallbacks, 0, sizeof(heapCallbacks)); /* Select callbacks */ heapCallbacks.heap_reference_callback = &cbReference; if ( gdata->primfields == JNI_TRUE ) { heapCallbacks.primitive_field_callback = &cbPrimFieldData; } if ( gdata->primarrays == JNI_TRUE ) { heapCallbacks.array_primitive_value_callback = &cbPrimArrayData; } followReferences(&heapCallbacks, (void*)NULL); /* Process reference information. */ object_reference_dump(env); object_clear_references(); reference_cleanup(); /* Dump the last thread traces and get the lists back we need */ tls_dump_traces(env); /* Write out footer for heap dump */ io_heap_footer(); } rawMonitorExit(gdata->data_access_lock); }
void site_heapdump(JNIEnv *env) { rawMonitorEnter(gdata->data_access_lock); { struct { int i; } user_data; /* FIXUP */ user_data.i = 0; /* Remove class dumped status, all classes must be dumped */ class_all_status_remove(CLASS_DUMPED); /* Clear in_heap_dump flag */ tls_clear_in_heap_dump(); /* Dump the last thread traces and get the lists back we need */ tls_dump_traces(env); /* Write header for heap dump */ io_heap_header(gdata->total_live_instances, gdata->total_live_bytes); /* Setup a clean reference table */ reference_init(); /* Walk over all reachable objects and dump out roots */ gdata->gref_serial_number_counter = gdata->gref_serial_number_start; /* Issue thread object for fake non-existent unknown thread * just in case someone refers to it. Real threads are handled * during iterate over reachable objects. */ io_heap_root_thread_object(0, gdata->unknown_thread_serial_num, trace_get_serial_number(gdata->system_trace_index)); /* Iterate over heap and get the real stuff */ iterateOverReachableObjects(&root_object, &stack_object, &reference_object, (void*)&user_data); /* Process reference information. */ object_reference_dump(env); object_clear_references(); reference_cleanup(); /* Dump the last thread traces and get the lists back we need */ tls_dump_traces(env); /* Write out footer for heap dump */ io_heap_footer(); } rawMonitorExit(gdata->data_access_lock); }
/* Walk all references for an ObjectIndex and construct the hprof INST dump. */ static void dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list) { jvmtiPrimitiveType primType; SiteIndex site_index; SerialNumber trace_serial_num; RefIndex index; ObjectIndex class_index; jlong size; ClassIndex cnum; char *sig; void *elements; jint num_elements; jint num_bytes; ObjectIndex *values; FieldInfo *fields; jvalue *fvalues; jint n_fields; jboolean skip_fields; jint n_fields_set; ObjectKind kind; TraceIndex trace_index; jboolean is_array; jboolean is_prim_array; HPROF_ASSERT(object_index!=0); kind = object_get_kind(object_index); if ( kind == OBJECT_CLASS ) { return; } site_index = object_get_site(object_index); HPROF_ASSERT(site_index!=0); cnum = site_get_class_index(site_index); HPROF_ASSERT(cnum!=0); size = (jlong)object_get_size(object_index); trace_index = site_get_trace_index(site_index); HPROF_ASSERT(trace_index!=0); trace_serial_num = trace_get_serial_number(trace_index); sig = string_get(class_get_signature(cnum)); class_index = class_get_object_index(cnum); values = NULL; elements = NULL; num_elements = 0; num_bytes = 0; n_fields = 0; skip_fields = JNI_FALSE; n_fields_set = 0; fields = NULL; fvalues = NULL; index = list; is_array = JNI_FALSE; is_prim_array = JNI_FALSE; if ( sig[0] != JVM_SIGNATURE_ARRAY ) { if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) { /* Trouble getting all the fields, can't trust field index values */ skip_fields = JNI_TRUE; /* It is assumed that the reason why we didn't get the fields * was because the class is not prepared. */ if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) { if ( list != 0 ) { dump_ref_list(list); debug_message("Instance of unprepared class with refs: %s\n", sig); } else { debug_message("Instance of unprepared class without refs: %s\n", sig); } HPROF_ERROR(JNI_FALSE, "Big Trouble with unprepared class instances"); } } if ( n_fields > 0 ) { fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue)); (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue)); } } else { is_array = JNI_TRUE; if ( sig[0] != 0 && sigToPrimSize(sig+1) != 0 ) { is_prim_array = JNI_TRUE; } } while ( index != 0 ) { RefInfo *info; jvalue ovalue; static jvalue empty_value; info = get_info(index); /* Process reference objects, many not used right now. */ switch ( info->flavor ) { case INFO_OBJECT_REF_DATA: switch ( info->refKind ) { case JVMTI_HEAP_REFERENCE_SIGNERS: case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN: case JVMTI_HEAP_REFERENCE_CLASS_LOADER: case JVMTI_HEAP_REFERENCE_INTERFACE: case JVMTI_HEAP_REFERENCE_STATIC_FIELD: case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: /* Should never be seen on an instance dump */ HPROF_ASSERT(0); break; case JVMTI_HEAP_REFERENCE_FIELD: if ( skip_fields == JNI_TRUE ) { break; } HPROF_ASSERT(is_array!=JNI_TRUE); ovalue = empty_value; ovalue.i = info->object_index; fill_in_field_value(list, fields, fvalues, n_fields, info->index, ovalue, 0); n_fields_set++; HPROF_ASSERT(n_fields_set <= n_fields); break; case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: /* We get each object element one at a time. */ HPROF_ASSERT(is_array==JNI_TRUE); HPROF_ASSERT(is_prim_array!=JNI_TRUE); if ( num_elements <= info->index ) { int nbytes; if ( values == NULL ) { num_elements = info->index + 1; nbytes = num_elements*(int)sizeof(ObjectIndex); values = (ObjectIndex*)HPROF_MALLOC(nbytes); (void)memset(values, 0, nbytes); } else { void *new_values; int new_size; int obytes; obytes = num_elements*(int)sizeof(ObjectIndex); new_size = info->index + 1; nbytes = new_size*(int)sizeof(ObjectIndex); new_values = (void*)HPROF_MALLOC(nbytes); (void)memcpy(new_values, values, obytes); (void)memset(((char*)new_values)+obytes, 0, nbytes-obytes); HPROF_FREE(values); num_elements = new_size; values = new_values; } } HPROF_ASSERT(values[info->index]==0); values[info->index] = info->object_index; break; default: /* Ignore, not needed */ break; } break; case INFO_PRIM_FIELD_DATA: if ( skip_fields == JNI_TRUE ) { break; } HPROF_ASSERT(info->primType!=0); HPROF_ASSERT(info->length==-1); HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_FIELD); HPROF_ASSERT(is_array!=JNI_TRUE); ovalue = get_key_value(index); fill_in_field_value(list, fields, fvalues, n_fields, info->index, ovalue, info->primType); n_fields_set++; HPROF_ASSERT(n_fields_set <= n_fields); break; case INFO_PRIM_ARRAY_DATA: /* Should only be one, and it's handled below */ HPROF_ASSERT(info->refKind==0); /* We assert that nothing else was saved with this array */ HPROF_ASSERT(index==list&&info->next==0); HPROF_ASSERT(is_array==JNI_TRUE); HPROF_ASSERT(is_prim_array==JNI_TRUE); primType = info->primType; elements = get_key_elements(index, primType, &num_elements, &num_bytes); HPROF_ASSERT(info->length==num_elements); size = num_bytes; break; default: HPROF_ASSERT(0); break; } index = info->next; } if ( is_array == JNI_TRUE ) { if ( is_prim_array == JNI_TRUE ) { HPROF_ASSERT(values==NULL); io_heap_prim_array(object_index, trace_serial_num, (jint)size, num_elements, sig, elements); } else { HPROF_ASSERT(elements==NULL); io_heap_object_array(object_index, trace_serial_num, (jint)size, num_elements, sig, values, class_index); } } else { io_heap_instance_dump(cnum, object_index, trace_serial_num, class_index, (jint)size, sig, fields, fvalues, n_fields); } if ( values != NULL ) { HPROF_FREE(values); } if ( fvalues != NULL ) { HPROF_FREE(fvalues); } if ( elements != NULL ) { /* Do NOT free elements, it's a key in the table, leave it be */ } }
/* Walk all references for an ObjectIndex and construct the hprof CLASS dump. */ static void dump_class_and_supers(JNIEnv *env, ObjectIndex object_index, RefIndex list) { SiteIndex site_index; SerialNumber trace_serial_num; RefIndex index; ClassIndex super_cnum; ObjectIndex super_index; LoaderIndex loader_index; ObjectIndex signers_index; ObjectIndex domain_index; FieldInfo *fields; jvalue *fvalues; jint n_fields; jboolean skip_fields; jint n_fields_set; jlong size; ClassIndex cnum; char *sig; ObjectKind kind; TraceIndex trace_index; Stack *cpool_values; ConstantPoolValue *cpool; jint cpool_count; HPROF_ASSERT(object_index!=0); kind = object_get_kind(object_index); if ( kind != OBJECT_CLASS ) { return; } site_index = object_get_site(object_index); HPROF_ASSERT(site_index!=0); cnum = site_get_class_index(site_index); HPROF_ASSERT(cnum!=0); if ( class_get_status(cnum) & CLASS_DUMPED ) { return; } class_add_status(cnum, CLASS_DUMPED); size = (jlong)object_get_size(object_index); super_index = 0; super_cnum = class_get_super(cnum); if ( super_cnum != 0 ) { super_index = class_get_object_index(super_cnum); if ( super_index != 0 ) { dump_class_and_supers(env, super_index, object_get_references(super_index)); } } trace_index = site_get_trace_index(site_index); HPROF_ASSERT(trace_index!=0); trace_serial_num = trace_get_serial_number(trace_index); sig = string_get(class_get_signature(cnum)); loader_index = class_get_loader(cnum); signers_index = 0; domain_index = 0; /* Get field information */ n_fields = 0; skip_fields = JNI_FALSE; n_fields_set = 0; fields = NULL; fvalues = NULL; if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) { /* Problems getting all the fields, can't trust field index values */ skip_fields = JNI_TRUE; /* Class with no references at all? (ok to be unprepared if list==0?) */ if ( list != 0 ) { /* It is assumed that the reason why we didn't get the fields * was because the class is not prepared. */ if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) { dump_ref_list(list); debug_message("Unprepared class with references: %s\n", sig); } HPROF_ERROR(JNI_FALSE, "Trouble with unprepared classes"); } /* Why would an unprepared class contain references? */ } if ( n_fields > 0 ) { fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue)); (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue)); } /* We use a Stack just because it will automatically expand as needed */ cpool_values = stack_init(16, 16, sizeof(ConstantPoolValue)); cpool = NULL; cpool_count = 0; index = list; while ( index != 0 ) { RefInfo *info; jvalue ovalue; static jvalue empty_value; info = get_info(index); switch ( info->flavor ) { case INFO_OBJECT_REF_DATA: switch ( info->refKind ) { case JVMTI_HEAP_REFERENCE_FIELD: case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: /* Should never be seen on a class dump */ HPROF_ASSERT(0); break; case JVMTI_HEAP_REFERENCE_STATIC_FIELD: if ( skip_fields == JNI_TRUE ) { break; } ovalue = empty_value; ovalue.i = info->object_index; fill_in_field_value(list, fields, fvalues, n_fields, info->index, ovalue, 0); n_fields_set++; HPROF_ASSERT(n_fields_set <= n_fields); break; case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: { ConstantPoolValue cpv; ObjectIndex cp_object_index; SiteIndex cp_site_index; ClassIndex cp_cnum; cp_object_index = info->object_index; HPROF_ASSERT(cp_object_index!=0); cp_site_index = object_get_site(cp_object_index); HPROF_ASSERT(cp_site_index!=0); cp_cnum = site_get_class_index(cp_site_index); cpv.constant_pool_index = info->index; cpv.sig_index = class_get_signature(cp_cnum); cpv.value.i = cp_object_index; stack_push(cpool_values, (void*)&cpv); cpool_count++; break; } case JVMTI_HEAP_REFERENCE_SIGNERS: signers_index = info->object_index; break; case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN: domain_index = info->object_index; break; case JVMTI_HEAP_REFERENCE_CLASS_LOADER: case JVMTI_HEAP_REFERENCE_INTERFACE: default: /* Ignore, not needed */ break; } break; case INFO_PRIM_FIELD_DATA: if ( skip_fields == JNI_TRUE ) { break; } HPROF_ASSERT(info->primType!=0); HPROF_ASSERT(info->length==-1); HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_STATIC_FIELD); ovalue = get_key_value(index); fill_in_field_value(list, fields, fvalues, n_fields, info->index, ovalue, info->primType); n_fields_set++; HPROF_ASSERT(n_fields_set <= n_fields); break; case INFO_PRIM_ARRAY_DATA: default: /* Should never see these */ HPROF_ASSERT(0); break; } index = info->next; } /* Get constant pool data if we have any */ HPROF_ASSERT(cpool_count==stack_depth(cpool_values)); if ( cpool_count > 0 ) { cpool = (ConstantPoolValue*)stack_element(cpool_values, 0); } io_heap_class_dump(cnum, sig, object_index, trace_serial_num, super_index, loader_object_index(env, loader_index), signers_index, domain_index, (jint)size, cpool_count, cpool, n_fields, fields, fvalues); stack_term(cpool_values); if ( fvalues != NULL ) { HPROF_FREE(fvalues); } }
void site_write(JNIEnv *env, int flags, double cutoff) { HPROF_ASSERT(gdata->site_table!=NULL); LOG3("site_write", "flags", flags); if (flags & SITE_FORCE_GC) { runGC(); } HPROF_ASSERT(gdata->total_live_bytes!=0); rawMonitorEnter(gdata->data_access_lock); { IterateInfo iterate; int site_table_size; double accum_percent; void * comment_str; int i; int cutoff_count; int nbytes; accum_percent = 0; site_table_size = table_element_count(gdata->site_table); (void)memset(&iterate, 0, sizeof(iterate)); nbytes = site_table_size * (int)sizeof(SiteIndex); if ( nbytes > 0 ) { iterate.site_nums = HPROF_MALLOC(nbytes); (void)memset(iterate.site_nums, 0, nbytes); } iterate.count = 0; iterate.changed_only = flags & SITE_DUMP_INCREMENTAL; table_walk_items(gdata->site_table, &collect_iterator, &iterate); site_table_size = iterate.count; if (flags & SITE_SORT_BY_ALLOC) { comment_str = "allocated bytes"; qsort(iterate.site_nums, site_table_size, sizeof(SiteIndex), &qsort_compare_allocated_bytes); } else { comment_str = "live bytes"; qsort(iterate.site_nums, site_table_size, sizeof(SiteIndex), &qsort_compare_live_bytes); } trace_output_unmarked(env); cutoff_count = 0; for (i = 0; i < site_table_size; i++) { SiteInfo *info; SiteIndex index; double ratio; index= iterate.site_nums[i]; HPROF_ASSERT(index!=0); info = get_info(index); ratio = (double)info->n_live_bytes / (double)gdata->total_live_bytes; if (ratio < cutoff) { break; } cutoff_count++; } io_write_sites_header( comment_str, flags, cutoff, gdata->total_live_bytes, gdata->total_live_instances, gdata->total_alloced_bytes, gdata->total_alloced_instances, cutoff_count); for (i = 0; i < cutoff_count; i++) { SiteInfo *info; SiteKey *pkey; SiteIndex index; char *class_signature; double ratio; index = iterate.site_nums[i]; pkey = get_pkey(index); info = get_info(index); ratio = (double)info->n_live_bytes / (double)gdata->total_live_bytes; accum_percent += ratio; class_signature = string_get(class_get_signature(pkey->cnum)); io_write_sites_elem(i + 1, ratio, accum_percent, class_signature, class_get_serial_number(pkey->cnum), trace_get_serial_number(pkey->trace_index), info->n_live_bytes, info->n_live_instances, info->n_alloced_bytes, info->n_alloced_instances); } io_write_sites_footer(); table_walk_items(gdata->site_table, &mark_unchanged_iterator, NULL); if ( iterate.site_nums != NULL ) { HPROF_FREE(iterate.site_nums); } } rawMonitorExit(gdata->data_access_lock); }
/* JVMTI callback function. */ static jvmtiIterationControl JNICALL root_object(jvmtiHeapRootKind root_kind, jlong class_tag, jlong size, jlong* tag_ptr, void *user_data) { /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit * are allowed here (see the JVMTI Spec). */ ObjectIndex object_index; SiteIndex object_site_index; HPROF_ASSERT(tag_ptr!=NULL); if ( (*tag_ptr) != (jlong)0 ) { object_index = tag_extract(*tag_ptr); object_site_index = object_get_site(object_index); } else { object_site_index = site_find_or_create(find_cnum(class_tag), gdata->system_trace_index); object_index = object_new(object_site_index, (jint)size, OBJECT_SYSTEM, gdata->system_thread_serial_num); /* Create and set the tag. */ *tag_ptr = tag_create(object_index); } switch ( root_kind ) { case JVMTI_HEAP_ROOT_JNI_GLOBAL: { SerialNumber trace_serial_num; SerialNumber gref_serial_num; if ( object_site_index != 0 ) { SiteKey *pkey; TraceIndex trace_index; pkey = get_pkey(object_site_index); trace_index = pkey->trace_index; trace_serial_num = trace_get_serial_number(trace_index); } else { trace_serial_num = trace_get_serial_number(gdata->system_trace_index); } gref_serial_num = gdata->gref_serial_number_counter++; io_heap_root_jni_global(object_index, gref_serial_num, trace_serial_num); break; } case JVMTI_HEAP_ROOT_SYSTEM_CLASS: { char *sig; sig = "Unknown"; if ( object_site_index != 0 ) { SiteKey *pkey; pkey = get_pkey(object_site_index); sig = string_get(class_get_signature(pkey->cnum)); } io_heap_root_system_class(object_index, sig); break; } case JVMTI_HEAP_ROOT_MONITOR: { io_heap_root_monitor(object_index); break; } case JVMTI_HEAP_ROOT_THREAD: { SerialNumber thread_serial_num; if ( object_index != 0 ) { thread_serial_num = object_get_thread_serial_number(object_index); } else { thread_serial_num = gdata->system_thread_serial_num; } io_heap_root_thread(object_index, thread_serial_num); break; } case JVMTI_HEAP_ROOT_OTHER: { io_heap_root_unknown(object_index); break; } default: break; } return JVMTI_ITERATION_CONTINUE; }
/* JVMTI callback function. */ static jvmtiIterationControl JNICALL root_object(jvmtiHeapRootKind root_kind, jlong class_tag, jlong size, jlong* tag_ptr, void *user_data) { /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit * are allowed here (see the JVMTI Spec). */ ObjectIndex object_index; SiteIndex object_site_index; HPROF_ASSERT(tag_ptr!=NULL); switch ( root_kind ) { case JVMTI_HEAP_ROOT_JNI_GLOBAL: { SerialNumber trace_serial_num; SerialNumber gref_serial_num; TraceIndex trace_index; setup_tag_on_root(tag_ptr, class_tag, size, gdata->unknown_thread_serial_num, &object_index, &object_site_index); if ( object_site_index != 0 ) { SiteKey *pkey; pkey = get_pkey(object_site_index); trace_index = pkey->trace_index; } else { trace_index = gdata->system_trace_index; } trace_serial_num = trace_get_serial_number(trace_index); gref_serial_num = gdata->gref_serial_number_counter++; io_heap_root_jni_global(object_index, gref_serial_num, trace_serial_num); break; } case JVMTI_HEAP_ROOT_SYSTEM_CLASS: { char *sig; setup_tag_on_root(tag_ptr, class_tag, size, gdata->unknown_thread_serial_num, &object_index, &object_site_index); sig = "Unknown"; if ( object_site_index != 0 ) { SiteKey *pkey; pkey = get_pkey(object_site_index); sig = string_get(class_get_signature(pkey->cnum)); } io_heap_root_system_class(object_index, sig); break; } case JVMTI_HEAP_ROOT_MONITOR: { setup_tag_on_root(tag_ptr, class_tag, size, gdata->unknown_thread_serial_num, &object_index, NULL); io_heap_root_monitor(object_index); break; } case JVMTI_HEAP_ROOT_THREAD: { SerialNumber thread_serial_num; SerialNumber trace_serial_num; TraceIndex trace_index; TlsIndex tls_index; if ( (*tag_ptr) != (jlong)0 ) { setup_tag_on_root(tag_ptr, class_tag, size, 0, &object_index, &object_site_index); trace_index = site_get_trace_index(object_site_index); /* Hopefully the ThreadStart event put this thread's * correct serial number on it's object. */ thread_serial_num = object_get_thread_serial_number(object_index); } else { /* Rare situation that a Thread object is not tagged. * Create special unique thread serial number in this * case, probably means we never saw a thread start * or thread end, or even an allocation of the thread * object. */ thread_serial_num = gdata->thread_serial_number_counter++; setup_tag_on_root(tag_ptr, class_tag, size, thread_serial_num, &object_index, &object_site_index); trace_index = gdata->system_trace_index; } /* Get tls_index and set in_heap_dump, if we find it. */ tls_index = tls_find(thread_serial_num); if ( tls_index != 0 ) { tls_set_in_heap_dump(tls_index, 1); } trace_serial_num = trace_get_serial_number(trace_index); /* Issue thread object (must be before thread root) */ io_heap_root_thread_object(object_index, thread_serial_num, trace_serial_num); /* Issue thread root */ io_heap_root_thread(object_index, thread_serial_num); break; } case JVMTI_HEAP_ROOT_OTHER: { setup_tag_on_root(tag_ptr, class_tag, size, gdata->unknown_thread_serial_num, &object_index, NULL); io_heap_root_unknown(object_index); break; } default: { setup_tag_on_root(tag_ptr, class_tag, size, gdata->unknown_thread_serial_num, NULL, NULL); break; } } return JVMTI_ITERATION_CONTINUE; }
/* FollowReferences heap_reference_callback */ static jint JNICALL cbReference(jvmtiHeapReferenceKind reference_kind, const jvmtiHeapReferenceInfo* reference_info, jlong class_tag, jlong referrer_class_tag, jlong size, jlong* tag_ptr, jlong* referrer_tag_ptr, jint length, void* user_data) { ObjectIndex object_index; /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit * are allowed here (see the JVMTI Spec). */ HPROF_ASSERT(tag_ptr!=NULL); HPROF_ASSERT(class_tag!=(jlong)0); if ( class_tag == (jlong)0 ) { /* We can't do anything with a class_tag==0, just skip it */ return JVMTI_VISIT_OBJECTS; } switch ( reference_kind ) { case JVMTI_HEAP_REFERENCE_FIELD: case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: case JVMTI_HEAP_REFERENCE_CLASS_LOADER: case JVMTI_HEAP_REFERENCE_SIGNERS: case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN: case JVMTI_HEAP_REFERENCE_INTERFACE: case JVMTI_HEAP_REFERENCE_STATIC_FIELD: case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: return objectReference(reference_kind, reference_info, class_tag, size, tag_ptr, referrer_tag_ptr, length); case JVMTI_HEAP_REFERENCE_JNI_GLOBAL: { SerialNumber trace_serial_num; SerialNumber gref_serial_num; TraceIndex trace_index; SiteIndex object_site_index; setup_tag_on_root(tag_ptr, class_tag, size, gdata->unknown_thread_serial_num, &object_index, &object_site_index); if ( object_site_index != 0 ) { SiteKey *pkey; pkey = get_pkey(object_site_index); trace_index = pkey->trace_index; } else { trace_index = gdata->system_trace_index; } trace_serial_num = trace_get_serial_number(trace_index); gref_serial_num = gdata->gref_serial_number_counter++; io_heap_root_jni_global(object_index, gref_serial_num, trace_serial_num); } break; case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: { char *sig; SerialNumber class_serial_num; SiteIndex object_site_index; setup_tag_on_root(tag_ptr, class_tag, size, gdata->unknown_thread_serial_num, &object_index, &object_site_index); sig = "Unknown"; class_serial_num = 0; if ( object_site_index != 0 ) { SiteKey *pkey; pkey = get_pkey(object_site_index); sig = string_get(class_get_signature(pkey->cnum)); class_serial_num = class_get_serial_number(pkey->cnum); } io_heap_root_system_class(object_index, sig, class_serial_num); } break; case JVMTI_HEAP_REFERENCE_MONITOR: setup_tag_on_root(tag_ptr, class_tag, size, gdata->unknown_thread_serial_num, &object_index, NULL); io_heap_root_monitor(object_index); break; case JVMTI_HEAP_REFERENCE_STACK_LOCAL: { SerialNumber thread_serial_num; jlong thread_tag; thread_tag = reference_info->stack_local.thread_tag; localReference(tag_ptr, class_tag, thread_tag, size, &object_index, &thread_serial_num); io_heap_root_java_frame(object_index, thread_serial_num, reference_info->stack_local.depth); } break; case JVMTI_HEAP_REFERENCE_JNI_LOCAL: { SerialNumber thread_serial_num; jlong thread_tag; thread_tag = reference_info->jni_local.thread_tag; localReference(tag_ptr, class_tag, thread_tag, size, &object_index, &thread_serial_num); io_heap_root_jni_local(object_index, thread_serial_num, reference_info->jni_local.depth); } break; case JVMTI_HEAP_REFERENCE_THREAD: { SerialNumber thread_serial_num; SerialNumber trace_serial_num; TraceIndex trace_index; SiteIndex object_site_index; TlsIndex tls_index; /* It is assumed that tag_ptr is referring to a * java.lang.Thread object here. */ if ( (*tag_ptr) != (jlong)0 ) { setup_tag_on_root(tag_ptr, class_tag, size, 0, &object_index, &object_site_index); trace_index = site_get_trace_index(object_site_index); /* Hopefully the ThreadStart event put this thread's * correct serial number on it's object. */ thread_serial_num = object_get_thread_serial_number(object_index); } else { /* Rare situation that a Thread object is not tagged. * Create special unique thread serial number in this * case, probably means we never saw a thread start * or thread end, or even an allocation of the thread * object. */ thread_serial_num = gdata->thread_serial_number_counter++; setup_tag_on_root(tag_ptr, class_tag, size, thread_serial_num, &object_index, &object_site_index); trace_index = gdata->system_trace_index; } /* Get tls_index and set in_heap_dump, if we find it. */ tls_index = tls_find(thread_serial_num); if ( tls_index != 0 ) { tls_set_in_heap_dump(tls_index, 1); } trace_serial_num = trace_get_serial_number(trace_index); /* Issue thread object (must be before thread root) */ io_heap_root_thread_object(object_index, thread_serial_num, trace_serial_num); /* Issue thread root */ io_heap_root_thread(object_index, thread_serial_num); } break; case JVMTI_HEAP_REFERENCE_OTHER: setup_tag_on_root(tag_ptr, class_tag, size, gdata->unknown_thread_serial_num, &object_index, NULL); io_heap_root_unknown(object_index); break; default: /* Ignore anything else */ break; } return JVMTI_VISIT_OBJECTS; }
/* Walk all references for an ObjectIndex and construct the hprof CLASS dump. */ static void dump_class_and_supers(JNIEnv *env, ObjectIndex object_index, RefIndex list) { SiteIndex site_index; SerialNumber trace_serial_num; RefIndex index; ClassIndex super_cnum; ObjectIndex super_index; LoaderIndex loader_index; ObjectIndex signers_index; ObjectIndex domain_index; FieldInfo *fields; jvalue *fvalues; jint n_fields; jlong size; ClassIndex cnum; char *sig; ObjectKind kind; TraceIndex trace_index; Stack *cpool_values; ConstantPoolValue *cpool; jint cpool_count; jboolean skip_fields; HPROF_ASSERT(object_index!=0); kind = object_get_kind(object_index); if ( kind != OBJECT_CLASS ) { return; } site_index = object_get_site(object_index); HPROF_ASSERT(site_index!=0); cnum = site_get_class_index(site_index); HPROF_ASSERT(cnum!=0); if ( class_get_status(cnum) & CLASS_DUMPED ) { return; } class_add_status(cnum, CLASS_DUMPED); size = (jlong)object_get_size(object_index); super_index = 0; super_cnum = class_get_super(cnum); if ( super_cnum != 0 ) { super_index = class_get_object_index(super_cnum); if ( super_index != 0 ) { dump_class_and_supers(env, super_index, object_get_references(super_index)); } } trace_index = site_get_trace_index(site_index); HPROF_ASSERT(trace_index!=0); trace_serial_num = trace_get_serial_number(trace_index); sig = string_get(class_get_signature(cnum)); n_fields = 0; fields = NULL; fvalues = NULL; skip_fields = JNI_TRUE; if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 0 ) { if ( n_fields > 0 ) { skip_fields = JNI_FALSE; fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue)); (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue)); } } /* We use a Stack just because it will automatically expand as needed */ cpool_values = stack_init(16, 16, sizeof(ConstantPoolValue)); cpool = NULL; cpool_count = 0; loader_index = class_get_loader(cnum); signers_index = 0; domain_index = 0; index = list; while ( index != 0 ) { RefInfo *info; info = get_info(index); /* Process reference objects, many not used right now. */ switch ( info->kind ) { case JVMTI_REFERENCE_STATIC_FIELD: /* If the class_tag is 0, it is possible for * info->element_index to be >= n_fields * and when this happens we just skip this field ref * for now. We probably have a java.lang.Object class * with n_fields==0, which is probably the wrong class. */ if (info->class_tag == (jlong)0 || skip_fields == JNI_TRUE ) { break; } HPROF_ASSERT(info->element_index < n_fields); if (info->element_index < n_fields) { ObjectIndex field_object_index; /* Field index is referrer_index from referrer_tag */ field_object_index = tag_to_object_index(info->object_tag); fvalues[info->element_index].i = field_object_index; } break; case JVMTI_REFERENCE_CONSTANT_POOL: { ConstantPoolValue cpv; ObjectIndex cp_object_index; SiteIndex cp_site_index; ClassIndex cp_cnum; cp_object_index = tag_to_object_index(info->object_tag); HPROF_ASSERT(cp_object_index!=0); cp_site_index = object_get_site(cp_object_index); HPROF_ASSERT(cp_site_index!=0); cp_cnum = site_get_class_index(cp_site_index); cpv.constant_pool_index = info->element_index; cpv.sig_index = class_get_signature(cp_cnum); cpv.value.i = cp_object_index; stack_push(cpool_values, (void*)&cpv); cpool_count++; break; } default: break; } index = info->next; } /* FIXUP: Fill rest of static primitive fields? If requested? */ /* Use: value = getStaticFieldValue(env, klass, field, field_sig); ? */ HPROF_ASSERT(cpool_count==stack_depth(cpool_values)); if ( cpool_count > 0 ) { cpool = (ConstantPoolValue*)stack_element(cpool_values, 0); } io_heap_class_dump(cnum, sig, object_index, trace_serial_num, super_index, loader_index, signers_index, domain_index, (jint)size, cpool_count, cpool, n_fields, fields, fvalues); stack_term(cpool_values); if ( fvalues != NULL ) { HPROF_FREE(fvalues); } }
/* Walk all references for an ObjectIndex and construct the hprof INST dump. */ static void dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list) { SiteIndex site_index; SerialNumber trace_serial_num; RefIndex index; ObjectIndex class_index; jlong size; ClassIndex cnum; char *sig; jint num_elements; jvalue *values; FieldInfo *fields; jvalue *fvalues; jint n_fields; ObjectKind kind; TraceIndex trace_index; jboolean skip_fields; HPROF_ASSERT(object_index!=0); kind = object_get_kind(object_index); if ( kind == OBJECT_CLASS ) { return; } site_index = object_get_site(object_index); HPROF_ASSERT(site_index!=0); cnum = site_get_class_index(site_index); HPROF_ASSERT(cnum!=0); size = (jlong)object_get_size(object_index); trace_index = site_get_trace_index(site_index); HPROF_ASSERT(trace_index!=0); trace_serial_num = trace_get_serial_number(trace_index); sig = string_get(class_get_signature(cnum)); class_index = class_get_object_index(cnum); values = NULL; num_elements = 0; n_fields = 0; fields = NULL; fvalues = NULL; index = list; skip_fields = JNI_TRUE; if ( sig[0] != JVM_SIGNATURE_ARRAY ) { if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 0 ) { if ( n_fields > 0 ) { skip_fields = JNI_FALSE; fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue)); (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue)); } } } while ( index != 0 ) { ObjectIndex field_object_index; RefInfo *info; info = get_info(index); /* Process reference objects, many not used right now. */ switch ( info->kind ) { case JVMTI_REFERENCE_FIELD: /* If the class_tag is 0, it is possible for * info->element_index to be >= n_fields * and when this happens we just skip this field ref * for now. We probably have a java.lang.Object class * with n_fields==0, which is probably the wrong class. */ if (info->class_tag == (jlong)0 || skip_fields == JNI_TRUE ) { break; } HPROF_ASSERT(info->element_index < n_fields); if (info->element_index < n_fields) { /* Field index is referrer_index from referrer_tag */ field_object_index = tag_to_object_index(info->object_tag); fvalues[info->element_index].i = field_object_index; } break; case JVMTI_REFERENCE_ARRAY_ELEMENT: /* Array element index is referrer_index in referrer_tag */ if ( num_elements <= info->element_index ) { int nbytes; if ( values == NULL ) { num_elements = info->element_index + 1; nbytes = num_elements*(int)sizeof(jvalue); values = (jvalue*)HPROF_MALLOC(nbytes); (void)memset(values, 0, nbytes); } else { void *new_values; int new_size; int obytes; obytes = num_elements*(int)sizeof(jvalue); new_size = info->element_index + 1; nbytes = new_size*(int)sizeof(jvalue); new_values = (jvalue*)HPROF_MALLOC(nbytes); (void)memcpy(new_values, values, obytes); (void)memset(((char*)new_values)+obytes, 0, nbytes-obytes); HPROF_FREE(values); num_elements = new_size; values = new_values; } } field_object_index = tag_to_object_index(info->object_tag); HPROF_ASSERT(values[info->element_index].i==0); values[info->element_index].i = field_object_index; break; default: break; } index = info->next; } if ( sig[0] == JVM_SIGNATURE_ARRAY ) { /* FIXUP: Fill primitive arrays? If requested? */ switch ( sig[1] ) { case JVM_SIGNATURE_CLASS: case JVM_SIGNATURE_ENUM: case JVM_SIGNATURE_ARRAY: io_heap_object_array(object_index, trace_serial_num, (jint)size, num_elements, class_index, values, sig); break; case JVM_SIGNATURE_BYTE: case JVM_SIGNATURE_BOOLEAN: io_heap_prim_array(object_index, (jint)size, trace_serial_num, num_elements, sig, values); break; case JVM_SIGNATURE_CHAR: case JVM_SIGNATURE_SHORT: io_heap_prim_array(object_index, (jint)size, trace_serial_num, num_elements, sig, values); break; case JVM_SIGNATURE_INT: case JVM_SIGNATURE_FLOAT: io_heap_prim_array(object_index, (jint)size, trace_serial_num, num_elements, sig, values); break; case JVM_SIGNATURE_DOUBLE: case JVM_SIGNATURE_LONG: io_heap_prim_array(object_index, (jint)size, trace_serial_num, num_elements, sig, values); break; default: HPROF_ASSERT(0); break; } } else { /* FIXUP: Fill rest of primitive fields? If requested? */ io_heap_instance_dump(cnum, object_index, trace_serial_num, class_index, (jint)size, sig, fields, fvalues, n_fields); } if ( values != NULL ) { HPROF_FREE(values); } if ( fvalues != NULL ) { HPROF_FREE(fvalues); } }