/* Add a instance field information to this cmap. */ static void add_inst_field_to_cmap(CmapInfo *cmap, HprofId id, HprofType ty) { int i; HPROF_ASSERT(cmap!=NULL); i = cmap->n_finfo++; if ( i+1 >= cmap->max_finfo ) { int osize; Finfo *new_finfo; osize = cmap->max_finfo; cmap->max_finfo += 12; new_finfo = (Finfo*)HPROF_MALLOC(cmap->max_finfo*(int)sizeof(Finfo)); (void)memset(new_finfo,0,cmap->max_finfo*(int)sizeof(Finfo)); if ( i == 0 ) { cmap->finfo = new_finfo; } else { (void)memcpy(new_finfo,cmap->finfo,osize*(int)sizeof(Finfo)); HPROF_FREE(cmap->finfo); cmap->finfo = new_finfo; } } cmap->finfo[i].id = id; cmap->finfo[i].ty = ty; }
/* Read the entire file into memory */ static void * get_binary_file_image(char *filename, int *pnbytes) { unsigned char *image; int fd; jlong nbytes; int nread; *pnbytes = 0; fd = md_open_binary(filename); CHECK_FOR_ERROR(fd>=0); if ( (nbytes = md_seek(fd, (jlong)-1)) == (jlong)-1 ) { HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to end of file"); } CHECK_FOR_ERROR(((jint)nbytes)>512); if ( md_seek(fd, (jlong)0) != (jlong)0 ) { HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to start of file"); } image = HPROF_MALLOC(((jint)nbytes)+1); CHECK_FOR_ERROR(image!=NULL); /* Read the entire file image into memory */ nread = md_read(fd, image, (jint)nbytes); if ( nread <= 0 ) { HPROF_ERROR(JNI_TRUE, "System read failed."); } CHECK_FOR_ERROR(((jint)nbytes)==nread); md_close(fd); *pnbytes = (jint)nbytes; return image; }
/* Add a new current_block to the Blocks* chain, adjust size if nbytes big. */ static void add_block(Blocks *blocks, int nbytes) { int header_size; int block_size; BlockHeader *block_header; HPROF_ASSERT(blocks!=NULL); HPROF_ASSERT(nbytes>0); header_size = real_size(blocks->alignment, sizeof(BlockHeader)); block_size = blocks->elem_size*blocks->population; if ( nbytes > block_size ) { block_size = real_size(blocks->alignment, nbytes); } block_header = (BlockHeader*)HPROF_MALLOC(block_size+header_size); block_header->next = NULL; block_header->bytes_left = block_size; block_header->next_pos = header_size; /* Link in new block */ if ( blocks->current_block != NULL ) { blocks->current_block->next = block_header; } blocks->current_block = block_header; if ( blocks->first_block == NULL ) { blocks->first_block = block_header; } }
/* Initialize a new Blocks */ Blocks * blocks_init(int alignment, int elem_size, int population) { Blocks *blocks; HPROF_ASSERT(alignment>0); HPROF_ASSERT(elem_size>0); HPROF_ASSERT(population>0); blocks = (Blocks*)HPROF_MALLOC(sizeof(Blocks)); blocks->alignment = alignment; blocks->elem_size = elem_size; blocks->population = population; blocks->first_block = NULL; blocks->current_block = NULL; return blocks; }
/* 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); }
/* Check all the heap tags in a heap dump */ static int check_tags(unsigned char *pstart, int nbytes) { unsigned char *p; int nrecord; struct LookupTable *utab; UmapInfo umap; check_printf("\nCHECK TAGS: starting\n"); utab = table_initialize("temp utf8 map", 64, 64, 512, sizeof(UmapInfo)); /* Walk the tags, assumes UTF8 tags are defined before used */ p = pstart; nrecord = 0; while ( p < (pstart+nbytes) ) { unsigned tag; unsigned size; int nheap_records; int npos; char *label; HprofId id, nm, sg, so, gr, gn; int i, li, num_elements; HprofType ty; SerialNumber trace_serial_num; SerialNumber thread_serial_num; SerialNumber class_serial_num; unsigned flags; unsigned depth; float cutoff; unsigned temp; jint nblive; jint nilive; jlong tbytes; jlong tinsts; jint total_samples; jint trace_count; nrecord++; /*LINTED*/ npos = (int)(p - pstart); tag = read_u1(&p); (void)read_u4(&p); /* microsecs */ size = read_u4(&p); #define CASE_TAG(name) case name: label = #name; switch ( tag ) { CASE_TAG(HPROF_UTF8) CHECK_FOR_ERROR(size>=(int)sizeof(HprofId)); id = read_id(&p); check_printf("#%d@%d: %s, sz=%d, name_id=0x%x, \"", nrecord, npos, label, size, id); num_elements = size-(int)sizeof(HprofId); check_raw(p, num_elements); check_printf("\"\n"); /* Create entry in umap */ umap.str = HPROF_MALLOC(num_elements+1); (void)strncpy(umap.str, (char*)p, (size_t)num_elements); umap.str[num_elements] = 0; (void)table_create_entry(utab, &id, sizeof(id), &umap); p += num_elements; break; CASE_TAG(HPROF_LOAD_CLASS) CHECK_FOR_ERROR(size==2*4+2*(int)sizeof(HprofId)); class_serial_num = read_u4(&p); CHECK_CLASS_SERIAL_NO(class_serial_num); id = read_id(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); nm = read_id(&p); check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u," " id=0x%x, trace_serial_num=%u, name_id=0x%x\n", nrecord, npos, label, size, class_serial_num, id, trace_serial_num, nm); break; CASE_TAG(HPROF_UNLOAD_CLASS) CHECK_FOR_ERROR(size==4); class_serial_num = read_u4(&p); CHECK_CLASS_SERIAL_NO(class_serial_num); check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u\n", nrecord, npos, label, size, class_serial_num); break; CASE_TAG(HPROF_FRAME) CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId)); id = read_id(&p); nm = read_id(&p); sg = read_id(&p); so = read_id(&p); class_serial_num = read_u4(&p); CHECK_CLASS_SERIAL_NO(class_serial_num); li = read_u4(&p); check_printf("#%d@%d: %s, sz=%d, ", nrecord, npos, label, size); check_print_utf8(utab, "id=", id); check_printf(" name_id=0x%x, sig_id=0x%x, source_id=0x%x," " class_serial_num=%u, lineno=%d\n", nm, sg, so, class_serial_num, li); break; CASE_TAG(HPROF_TRACE) CHECK_FOR_ERROR(size>=3*4); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); thread_serial_num = read_u4(&p); /* Can be 0 */ num_elements = read_u4(&p); check_printf("#%d@%d: %s, sz=%d, trace_serial_num=%u," " thread_serial_num=%u, nelems=%d [", nrecord, npos, label, size, trace_serial_num, thread_serial_num, num_elements); for(i=0; i< num_elements; i++) { check_printf("0x%x,", read_id(&p)); } check_printf("]\n"); break; CASE_TAG(HPROF_ALLOC_SITES) CHECK_FOR_ERROR(size>=2+4*4+2*8); flags = read_u2(&p); temp = read_u4(&p); cutoff = *((float*)&temp); nblive = read_u4(&p); nilive = read_u4(&p); tbytes = read_u8(&p); tinsts = read_u8(&p); num_elements = read_u4(&p); check_printf("#%d@%d: %s, sz=%d, flags=0x%x, cutoff=%g," " nblive=%d, nilive=%d, tbytes=(%d,%d)," " tinsts=(%d,%d), num_elements=%d\n", nrecord, npos, label, size, flags, cutoff, nblive, nilive, jlong_high(tbytes), jlong_low(tbytes), jlong_high(tinsts), jlong_low(tinsts), num_elements); for(i=0; i< num_elements; i++) { ty = read_u1(&p); class_serial_num = read_u4(&p); CHECK_CLASS_SERIAL_NO(class_serial_num); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); nblive = read_u4(&p); nilive = read_u4(&p); tbytes = read_u4(&p); tinsts = read_u4(&p); check_printf("\t %d: ty=%d, class_serial_num=%u," " trace_serial_num=%u, nblive=%d, nilive=%d," " tbytes=%d, tinsts=%d\n", i, ty, class_serial_num, trace_serial_num, nblive, nilive, (jint)tbytes, (jint)tinsts); } break; CASE_TAG(HPROF_HEAP_SUMMARY) CHECK_FOR_ERROR(size==2*4+2*8); nblive = read_u4(&p); nilive = read_u4(&p); tbytes = read_u8(&p); tinsts = read_u8(&p); check_printf("#%d@%d: %s, sz=%d," " nblive=%d, nilive=%d, tbytes=(%d,%d)," " tinsts=(%d,%d)\n", nrecord, npos, label, size, nblive, nilive, jlong_high(tbytes), jlong_low(tbytes), jlong_high(tinsts), jlong_low(tinsts)); break; CASE_TAG(HPROF_START_THREAD) CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId)); thread_serial_num = read_u4(&p); CHECK_THREAD_SERIAL_NO(thread_serial_num); id = read_id(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); nm = read_id(&p); gr = read_id(&p); gn = read_id(&p); check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u," " id=0x%x, trace_serial_num=%u, ", nrecord, npos, label, size, thread_serial_num, id, trace_serial_num); check_print_utf8(utab, "nm=", id); check_printf(" trace_serial_num=%u, nm=0x%x," " gr=0x%x, gn=0x%x\n", trace_serial_num, nm, gr, gn); break; CASE_TAG(HPROF_END_THREAD) CHECK_FOR_ERROR(size==4); thread_serial_num = read_u4(&p); CHECK_THREAD_SERIAL_NO(thread_serial_num); check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u\n", nrecord, npos, label, size, thread_serial_num); break; CASE_TAG(HPROF_HEAP_DUMP) check_printf("#%d@%d: BEGIN: %s, sz=%d\n", nrecord, npos, label, size); nheap_records = check_heap_tags(utab, p, size); check_printf("#%d@%d: END: %s, sz=%d, nheap_recs=%d\n", nrecord, npos, label, size, nheap_records); p += size; break; CASE_TAG(HPROF_HEAP_DUMP_SEGMENT) /* 1.0.2 */ check_printf("#%d@%d: BEGIN SEGMENT: %s, sz=%d\n", nrecord, npos, label, size); nheap_records = check_heap_tags(utab, p, size); check_printf("#%d@%d: END SEGMENT: %s, sz=%d, nheap_recs=%d\n", nrecord, npos, label, size, nheap_records); p += size; break; CASE_TAG(HPROF_HEAP_DUMP_END) /* 1.0.2 */ check_printf("#%d@%d: SEGMENT END: %s, sz=%d\n", nrecord, npos, label, size); break; CASE_TAG(HPROF_CPU_SAMPLES) CHECK_FOR_ERROR(size>=2*4); total_samples = read_u4(&p); trace_count = read_u4(&p); check_printf("#%d@%d: %s, sz=%d, total_samples=%d," " trace_count=%d\n", nrecord, npos, label, size, total_samples, trace_count); for(i=0; i< trace_count; i++) { num_elements = read_u4(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); check_printf("\t %d: samples=%d, trace_serial_num=%u\n", trace_serial_num, num_elements); } break; CASE_TAG(HPROF_CONTROL_SETTINGS) CHECK_FOR_ERROR(size==4+2); flags = read_u4(&p); depth = read_u2(&p); check_printf("#%d@%d: %s, sz=%d, flags=0x%x, depth=%d\n", nrecord, npos, label, size, flags, depth); break; default: label = "UNKNOWN"; check_printf("#%d@%d: %s, sz=%d\n", nrecord, npos, label, size); HPROF_ERROR(JNI_TRUE, "unknown record type"); p += size; break; } CHECK_FOR_ERROR(p<=(pstart+nbytes)); } check_flush(); CHECK_FOR_ERROR(p==(pstart+nbytes)); table_cleanup(utab, &utab_cleanup, NULL); return nrecord; }
/* 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); } }