/* Primitive array data callback for FollowReferences */ static jint JNICALL cbPrimArrayData(jlong class_tag, jlong size, jlong* tag_ptr, jint element_count, jvmtiPrimitiveType element_type, const void* elements, void* user_data) { ObjectIndex object_index; RefIndex ref_index; RefIndex prev_ref_index; HPROF_ASSERT(tag_ptr!=NULL); HPROF_ASSERT(class_tag!=(jlong)0); HPROF_ASSERT((*tag_ptr)!=(jlong)0); if ( class_tag == (jlong)0 || (*tag_ptr) == (jlong)0 ) { /* We can't do anything with a class_tag==0, just skip it */ return JVMTI_VISIT_OBJECTS; } /* Assume object has been tagged, get object index */ object_index = tag_extract((*tag_ptr)); /* Save string data */ prev_ref_index = object_get_references(object_index); ref_index = reference_prim_array(prev_ref_index, element_type, elements, element_count); object_set_references(object_index, ref_index); return JVMTI_VISIT_OBJECTS; }
/* JVMTI callback function. */ static jvmtiIterationControl JNICALL reference_object(jvmtiObjectReferenceKind reference_kind, jlong class_tag, jlong size, jlong* tag_ptr, jlong referrer_tag, jint referrer_index, void *user_data) { /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit * are allowed here (see the JVMTI Spec). */ RefIndex ref_index; RefIndex prev_ref_index; ObjectIndex referrer_object_index; ObjectIndex object_index; jlong object_tag; HPROF_ASSERT(tag_ptr!=NULL); HPROF_ASSERT(referrer_tag!=(jlong)0); if ( referrer_tag != (jlong)0 ) { referrer_object_index = tag_extract(referrer_tag); } else { return JVMTI_ITERATION_CONTINUE; } object_tag = *tag_ptr; if ( object_tag != (jlong)0 ) { object_index = tag_extract(object_tag); } else { SiteIndex site_index; site_index = site_find_or_create(find_cnum(class_tag), gdata->system_trace_index); object_index = object_new(site_index, (jint)size, OBJECT_SYSTEM, gdata->system_thread_serial_num); object_tag = tag_create(object_index); *tag_ptr = object_tag; } /* Save reference information */ prev_ref_index = object_get_references(referrer_object_index); ref_index = reference_new(prev_ref_index, reference_kind, class_tag, size, object_tag, referrer_index); object_set_references(referrer_object_index, ref_index); return JVMTI_ITERATION_CONTINUE; }
/* Primitive field data callback for FollowReferences */ static jint JNICALL cbPrimFieldData(jvmtiHeapReferenceKind reference_kind, const jvmtiHeapReferenceInfo* reference_info, jlong class_tag, jlong* tag_ptr, jvalue value, jvmtiPrimitiveType value_type, void* user_data) { ObjectIndex object_index; jint field_index; RefIndex ref_index; RefIndex prev_ref_index; HPROF_ASSERT(tag_ptr!=NULL); HPROF_ASSERT(class_tag!=(jlong)0); HPROF_ASSERT((*tag_ptr)!=(jlong)0); if ( class_tag == (jlong)0 || (*tag_ptr) == (jlong)0 ) { /* We can't do anything with a class_tag==0, just skip it */ return JVMTI_VISIT_OBJECTS; } /* If the field is 0, just skip it, we assume 0 */ if ( value.j == (jlong)0 ) { return JVMTI_VISIT_OBJECTS; } /* Get field index */ field_index = reference_info->field.index; /* We assume the object was tagged */ object_index = tag_extract((*tag_ptr)); /* Save primitive field data */ prev_ref_index = object_get_references(object_index); ref_index = reference_prim_field(prev_ref_index, reference_kind, value_type, value, field_index); object_set_references(object_index, ref_index); 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; 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); } }
/* Store away plain object reference information */ static jint objectReference(jvmtiHeapReferenceKind reference_kind, const jvmtiHeapReferenceInfo* reference_info, jlong class_tag, jlong size, jlong* tag_ptr, jlong* referrer_tag_ptr, jint length) { ObjectIndex object_index; jint reference_index; RefIndex ref_index; RefIndex prev_ref_index; ObjectIndex referrer_object_index; jlong object_tag; HPROF_ASSERT(tag_ptr!=NULL); HPROF_ASSERT(class_tag!=(jlong)0); HPROF_ASSERT(referrer_tag_ptr!=NULL); HPROF_ASSERT((*referrer_tag_ptr)!=(jlong)0); if ( class_tag == (jlong)0 || (*referrer_tag_ptr) == (jlong)0 ) { /* We can't do anything with a class_tag==0, just skip it */ return JVMTI_VISIT_OBJECTS; } switch ( reference_kind ) { default: /* Currently we don't need these */ return JVMTI_VISIT_OBJECTS; case JVMTI_HEAP_REFERENCE_FIELD: case JVMTI_HEAP_REFERENCE_STATIC_FIELD: reference_index = reference_info->field.index; break; case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: reference_index = reference_info->array.index; break; case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: reference_index = reference_info->constant_pool.index; break; case JVMTI_HEAP_REFERENCE_SIGNERS: case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN: case JVMTI_HEAP_REFERENCE_CLASS_LOADER: case JVMTI_HEAP_REFERENCE_INTERFACE: reference_index = 0; break; } /* We assume the referrer is tagged */ referrer_object_index = tag_extract((*referrer_tag_ptr)); /* Now check the referree */ object_tag = *tag_ptr; if ( object_tag != (jlong)0 ) { object_index = tag_extract(object_tag); } else { /* Create and set the tag. */ object_tag = make_new_tag(class_tag, size, gdata->system_trace_index, gdata->unknown_thread_serial_num, &object_index, NULL); *tag_ptr = object_tag; } HPROF_ASSERT(object_index!=0); /* Save reference information */ prev_ref_index = object_get_references(referrer_object_index); ref_index = reference_obj(prev_ref_index, reference_kind, object_index, reference_index, length); object_set_references(referrer_object_index, ref_index); 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); } }