0N/A/*
2362N/A * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
0N/A *
0N/A * Redistribution and use in source and binary forms, with or without
0N/A * modification, are permitted provided that the following conditions
0N/A * are met:
0N/A *
0N/A * - Redistributions of source code must retain the above copyright
0N/A * notice, this list of conditions and the following disclaimer.
0N/A *
0N/A * - Redistributions in binary form must reproduce the above copyright
0N/A * notice, this list of conditions and the following disclaimer in the
0N/A * documentation and/or other materials provided with the distribution.
0N/A *
2362N/A * - Neither the name of Oracle nor the names of its
0N/A * contributors may be used to endorse or promote products derived
0N/A * from this software without specific prior written permission.
0N/A *
0N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
0N/A * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0N/A * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0N/A * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0N/A * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0N/A * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0N/A * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0N/A * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0N/A * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0N/A * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0N/A * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0N/A */
0N/A
4378N/A/*
4378N/A * This source code is provided to illustrate the usage of a given feature
4378N/A * or technique and has been deliberately simplified. Additional steps
4378N/A * required for a production-quality application, such as security checks,
4378N/A * input validation and proper error handling, might not be present in
4378N/A * this sample code.
4378N/A */
4378N/A
4378N/A
0N/A/* Object references table (used in hprof_object.c). */
0N/A
0N/A/*
0N/A * This table is used by the object table to store object reference
0N/A * and primitive data information obtained from iterations over the
0N/A * heap (see hprof_site.c).
0N/A *
0N/A * Most of these table entries have no Key, but the key is used to store
0N/A * the primitive array and primitive field jvalue. None of these entries
0N/A * are ever looked up, there will be no hash table, use of the
0N/A * LookupTable was just an easy way to handle a unbounded table of
0N/A * entries. The object table (see hprof_object.c) will completely
0N/A * free this reference table after each heap dump or after processing the
0N/A * references and primitive data.
0N/A *
0N/A * The hprof format required this accumulation of all heap iteration
0N/A * references and primitive data from objects in order to compose an
0N/A * hprof records for it.
0N/A *
0N/A * This file contains detailed understandings of how an hprof CLASS
0N/A * and INSTANCE dump is constructed, most of this is derived from the
0N/A * original hprof code, but some has been derived by reading the HAT
0N/A * code that accepts this format.
0N/A *
0N/A */
0N/A
0N/A#include "hprof.h"
0N/A
0N/A/* The flavor of data being saved in the RefInfo */
0N/Aenum {
0N/A INFO_OBJECT_REF_DATA = 1,
0N/A INFO_PRIM_FIELD_DATA = 2,
0N/A INFO_PRIM_ARRAY_DATA = 3
0N/A};
0N/A
0N/A/* Reference information, object reference or primitive data information */
0N/Atypedef struct RefInfo {
0N/A ObjectIndex object_index; /* If an object reference, the referree index */
0N/A jint index; /* If array or field, array or field index */
0N/A jint length; /* If array the element count, if not -1 */
0N/A RefIndex next; /* The next table element */
0N/A unsigned flavor : 8; /* INFO_*, flavor of RefInfo */
0N/A unsigned refKind : 8; /* The kind of reference */
0N/A unsigned primType : 8; /* If primitive data involved, it's type */
0N/A} RefInfo;
0N/A
0N/A/* Private internal functions. */
0N/A
0N/A/* Get the RefInfo structure from an entry */
0N/Astatic RefInfo *
0N/Aget_info(RefIndex index)
0N/A{
0N/A RefInfo *info;
0N/A
0N/A info = (RefInfo*)table_get_info(gdata->reference_table, index);
0N/A return info;
0N/A}
0N/A
0N/A/* Get a jvalue that was stored as the key. */
0N/Astatic jvalue
0N/Aget_key_value(RefIndex index)
0N/A{
0N/A void *key;
0N/A int len;
0N/A jvalue value;
0N/A static jvalue empty_value;
0N/A
0N/A key = NULL;
0N/A table_get_key(gdata->reference_table, index, &key, &len);
0N/A HPROF_ASSERT(key!=NULL);
0N/A HPROF_ASSERT(len==(int)sizeof(jvalue));
0N/A if ( key != NULL ) {
0N/A (void)memcpy(&value, key, (int)sizeof(jvalue));
0N/A } else {
0N/A value = empty_value;
0N/A }
0N/A return value;
0N/A}
0N/A
0N/A/* Get size of a primitive type */
0N/Astatic jint
0N/Aget_prim_size(jvmtiPrimitiveType primType)
0N/A{
0N/A jint size;
0N/A
0N/A switch ( primType ) {
0N/A case JVMTI_PRIMITIVE_TYPE_BOOLEAN:
0N/A size = (jint)sizeof(jboolean);
0N/A break;
0N/A case JVMTI_PRIMITIVE_TYPE_BYTE:
0N/A size = (jint)sizeof(jbyte);
0N/A break;
0N/A case JVMTI_PRIMITIVE_TYPE_CHAR:
0N/A size = (jint)sizeof(jchar);
0N/A break;
0N/A case JVMTI_PRIMITIVE_TYPE_SHORT:
0N/A size = (jint)sizeof(jshort);
0N/A break;
0N/A case JVMTI_PRIMITIVE_TYPE_INT:
0N/A size = (jint)sizeof(jint);
0N/A break;
0N/A case JVMTI_PRIMITIVE_TYPE_FLOAT:
0N/A size = (jint)sizeof(jfloat);
0N/A break;
0N/A case JVMTI_PRIMITIVE_TYPE_LONG:
0N/A size = (jint)sizeof(jlong);
0N/A break;
0N/A case JVMTI_PRIMITIVE_TYPE_DOUBLE:
0N/A size = (jint)sizeof(jdouble);
0N/A break;
0N/A default:
0N/A HPROF_ASSERT(0);
0N/A size = 1;
0N/A break;
0N/A }
0N/A return size;
0N/A}
0N/A
0N/A/* Get a void* elements array that was stored as the key. */
0N/Astatic void *
0N/Aget_key_elements(RefIndex index, jvmtiPrimitiveType primType,
0N/A jint *nelements, jint *nbytes)
0N/A{
0N/A void *key;
0N/A jint byteLen;
0N/A
0N/A HPROF_ASSERT(nelements!=NULL);
0N/A HPROF_ASSERT(nbytes!=NULL);
0N/A
0N/A table_get_key(gdata->reference_table, index, &key, &byteLen);
0N/A HPROF_ASSERT(byteLen>=0);
0N/A HPROF_ASSERT(byteLen!=0?key!=NULL:key==NULL);
0N/A *nbytes = byteLen;
0N/A *nelements = byteLen / get_prim_size(primType);
0N/A return key;
0N/A}
0N/A
0N/A/* Dump a RefInfo* structure */
0N/Astatic void
0N/Adump_ref_info(RefInfo *info)
0N/A{
0N/A debug_message("[%d]: flavor=%d"
0N/A ", refKind=%d"
0N/A ", primType=%d"
0N/A ", object_index=0x%x"
0N/A ", length=%d"
0N/A ", next=0x%x"
0N/A "\n",
0N/A info->index,
0N/A info->flavor,
0N/A info->refKind,
0N/A info->primType,
0N/A info->object_index,
0N/A info->length,
0N/A info->next);
0N/A}
0N/A
0N/A/* Dump a RefIndex list */
0N/Astatic void
0N/Adump_ref_list(RefIndex list)
0N/A{
0N/A RefInfo *info;
0N/A RefIndex index;
0N/A
0N/A debug_message("\nFOLLOW REFERENCES RETURNED:\n");
0N/A index = list;
0N/A while ( index != 0 ) {
0N/A info = get_info(index);
0N/A dump_ref_info(info);
0N/A index = info->next;
0N/A }
0N/A}
0N/A
0N/A/* Dump information about a field and what ref data we had on it */
0N/Astatic void
0N/Adump_field(FieldInfo *fields, jvalue *fvalues, int n_fields,
0N/A jint index, jvalue value, jvmtiPrimitiveType primType)
0N/A{
0N/A ClassIndex cnum;
0N/A StringIndex name;
0N/A StringIndex sig;
0N/A
0N/A cnum = fields[index].cnum;
0N/A name = fields[index].name_index;
0N/A sig = fields[index].sig_index;
0N/A debug_message("[%d] %s \"%s\" \"%s\"",
0N/A index,
0N/A cnum!=0?string_get(class_get_signature(cnum)):"?",
0N/A name!=0?string_get(name):"?",
0N/A sig!=0?string_get(sig):"?");
0N/A if ( fields[index].primType!=0 || fields[index].primType!=primType ) {
0N/A debug_message(" (primType=%d(%c)",
0N/A fields[index].primType,
0N/A primTypeToSigChar(fields[index].primType));
0N/A if ( primType != fields[index].primType ) {
0N/A debug_message(", got %d(%c)",
0N/A primType,
0N/A primTypeToSigChar(primType));
0N/A }
0N/A debug_message(")");
0N/A } else {
0N/A debug_message("(ty=OBJ)");
0N/A }
0N/A if ( value.j != (jlong)0 || fvalues[index].j != (jlong)0 ) {
0N/A debug_message(" val=[0x%08x,0x%08x] or [0x%08x,0x%08x]",
0N/A jlong_high(value.j), jlong_low(value.j),
0N/A jlong_high(fvalues[index].j), jlong_low(fvalues[index].j));
0N/A }
0N/A debug_message("\n");
0N/A}
0N/A
0N/A/* Dump all the fields of interest */
0N/Astatic void
0N/Adump_fields(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields)
0N/A{
0N/A int i;
0N/A
0N/A debug_message("\nHPROF LIST OF ALL FIELDS:\n");
0N/A for ( i = 0 ; i < n_fields ; i++ ) {
0N/A if ( fields[i].name_index != 0 ) {
0N/A dump_field(fields, fvalues, n_fields, i, fvalues[i], fields[i].primType);
0N/A }
0N/A }
0N/A dump_ref_list(list);
0N/A}
0N/A
0N/A/* Verify field data */
0N/Astatic void
0N/Averify_field(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields,
0N/A jint index, jvalue value, jvmtiPrimitiveType primType)
0N/A{
0N/A HPROF_ASSERT(fvalues != NULL);
0N/A HPROF_ASSERT(n_fields > 0);
0N/A HPROF_ASSERT(index < n_fields);
0N/A HPROF_ASSERT(index >= 0 );
0N/A if ( primType!=fields[index].primType ) {
0N/A dump_fields(list, fields, fvalues, n_fields);
0N/A debug_message("\nPROBLEM WITH:\n");
0N/A dump_field(fields, fvalues, n_fields, index, value, primType);
0N/A debug_message("\n");
0N/A HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data");
0N/A }
0N/A if ( primType == JVMTI_PRIMITIVE_TYPE_BOOLEAN &&
0N/A ( value.b != 1 && value.b != 0 ) ) {
0N/A dump_fields(list, fields, fvalues, n_fields);
0N/A debug_message("\nPROBLEM WITH:\n");
0N/A dump_field(fields, fvalues, n_fields, index, value, primType);
0N/A debug_message("\n");
0N/A HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data");
0N/A }
0N/A}
0N/A
0N/A/* Fill in a field value, making sure the index is safe */
0N/Astatic void
0N/Afill_in_field_value(RefIndex list, FieldInfo *fields, jvalue *fvalues,
0N/A int n_fields, jint index, jvalue value,
0N/A jvmtiPrimitiveType primType)
0N/A{
0N/A HPROF_ASSERT(fvalues != NULL);
0N/A HPROF_ASSERT(n_fields > 0);
0N/A HPROF_ASSERT(index < n_fields);
0N/A HPROF_ASSERT(index >= 0 );
0N/A HPROF_ASSERT(fvalues[index].j==(jlong)0);
0N/A verify_field(list, fields, fvalues, n_fields, index, value, primType);
0N/A if (index >= 0 && index < n_fields) {
0N/A fvalues[index] = value;
0N/A }
0N/A}
0N/A
0N/A/* Walk all references for an ObjectIndex and construct the hprof CLASS dump. */
0N/Astatic void
0N/Adump_class_and_supers(JNIEnv *env, ObjectIndex object_index, RefIndex list)
0N/A{
0N/A SiteIndex site_index;
0N/A SerialNumber trace_serial_num;
0N/A RefIndex index;
0N/A ClassIndex super_cnum;
0N/A ObjectIndex super_index;
0N/A LoaderIndex loader_index;
0N/A ObjectIndex signers_index;
0N/A ObjectIndex domain_index;
0N/A FieldInfo *fields;
0N/A jvalue *fvalues;
0N/A jint n_fields;
0N/A jboolean skip_fields;
0N/A jint n_fields_set;
0N/A jlong size;
0N/A ClassIndex cnum;
0N/A char *sig;
0N/A ObjectKind kind;
0N/A TraceIndex trace_index;
0N/A Stack *cpool_values;
0N/A ConstantPoolValue *cpool;
0N/A jint cpool_count;
0N/A
0N/A HPROF_ASSERT(object_index!=0);
0N/A kind = object_get_kind(object_index);
0N/A if ( kind != OBJECT_CLASS ) {
0N/A return;
0N/A }
0N/A site_index = object_get_site(object_index);
0N/A HPROF_ASSERT(site_index!=0);
0N/A cnum = site_get_class_index(site_index);
0N/A HPROF_ASSERT(cnum!=0);
0N/A if ( class_get_status(cnum) & CLASS_DUMPED ) {
0N/A return;
0N/A }
0N/A class_add_status(cnum, CLASS_DUMPED);
0N/A size = (jlong)object_get_size(object_index);
0N/A
0N/A super_index = 0;
0N/A super_cnum = class_get_super(cnum);
0N/A if ( super_cnum != 0 ) {
0N/A super_index = class_get_object_index(super_cnum);
0N/A if ( super_index != 0 ) {
0N/A dump_class_and_supers(env, super_index,
0N/A object_get_references(super_index));
0N/A }
0N/A }
0N/A
0N/A trace_index = site_get_trace_index(site_index);
0N/A HPROF_ASSERT(trace_index!=0);
0N/A trace_serial_num = trace_get_serial_number(trace_index);
0N/A sig = string_get(class_get_signature(cnum));
0N/A loader_index = class_get_loader(cnum);
0N/A signers_index = 0;
0N/A domain_index = 0;
0N/A
0N/A /* Get field information */
0N/A n_fields = 0;
0N/A skip_fields = JNI_FALSE;
0N/A n_fields_set = 0;
0N/A fields = NULL;
0N/A fvalues = NULL;
0N/A if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) {
0N/A /* Problems getting all the fields, can't trust field index values */
0N/A skip_fields = JNI_TRUE;
0N/A /* Class with no references at all? (ok to be unprepared if list==0?) */
0N/A if ( list != 0 ) {
0N/A /* It is assumed that the reason why we didn't get the fields
0N/A * was because the class is not prepared.
0N/A */
0N/A if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) {
0N/A dump_ref_list(list);
0N/A debug_message("Unprepared class with references: %s\n",
0N/A sig);
0N/A }
0N/A HPROF_ERROR(JNI_FALSE, "Trouble with unprepared classes");
0N/A }
0N/A /* Why would an unprepared class contain references? */
0N/A }
0N/A if ( n_fields > 0 ) {
0N/A fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue));
0N/A (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue));
0N/A }
0N/A
0N/A /* We use a Stack just because it will automatically expand as needed */
0N/A cpool_values = stack_init(16, 16, sizeof(ConstantPoolValue));
0N/A cpool = NULL;
0N/A cpool_count = 0;
0N/A
0N/A index = list;
0N/A while ( index != 0 ) {
0N/A RefInfo *info;
0N/A jvalue ovalue;
0N/A static jvalue empty_value;
0N/A
0N/A info = get_info(index);
0N/A
0N/A switch ( info->flavor ) {
0N/A case INFO_OBJECT_REF_DATA:
0N/A switch ( info->refKind ) {
0N/A case JVMTI_HEAP_REFERENCE_FIELD:
0N/A case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
0N/A /* Should never be seen on a class dump */
0N/A HPROF_ASSERT(0);
0N/A break;
0N/A case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
0N/A if ( skip_fields == JNI_TRUE ) {
0N/A break;
0N/A }
0N/A ovalue = empty_value;
0N/A ovalue.i = info->object_index;
0N/A fill_in_field_value(list, fields, fvalues, n_fields,
0N/A info->index, ovalue, 0);
0N/A n_fields_set++;
0N/A HPROF_ASSERT(n_fields_set <= n_fields);
0N/A break;
0N/A case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: {
0N/A ConstantPoolValue cpv;
0N/A ObjectIndex cp_object_index;
0N/A SiteIndex cp_site_index;
0N/A ClassIndex cp_cnum;
0N/A
0N/A cp_object_index = info->object_index;
0N/A HPROF_ASSERT(cp_object_index!=0);
0N/A cp_site_index = object_get_site(cp_object_index);
0N/A HPROF_ASSERT(cp_site_index!=0);
0N/A cp_cnum = site_get_class_index(cp_site_index);
0N/A cpv.constant_pool_index = info->index;
0N/A cpv.sig_index = class_get_signature(cp_cnum);
0N/A cpv.value.i = cp_object_index;
0N/A stack_push(cpool_values, (void*)&cpv);
0N/A cpool_count++;
0N/A break;
0N/A }
0N/A case JVMTI_HEAP_REFERENCE_SIGNERS:
0N/A signers_index = info->object_index;
0N/A break;
0N/A case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
0N/A domain_index = info->object_index;
0N/A break;
0N/A case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
0N/A case JVMTI_HEAP_REFERENCE_INTERFACE:
0N/A default:
0N/A /* Ignore, not needed */
0N/A break;
0N/A }
0N/A break;
0N/A case INFO_PRIM_FIELD_DATA:
0N/A if ( skip_fields == JNI_TRUE ) {
0N/A break;
0N/A }
0N/A HPROF_ASSERT(info->primType!=0);
0N/A HPROF_ASSERT(info->length==-1);
0N/A HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_STATIC_FIELD);
0N/A ovalue = get_key_value(index);
0N/A fill_in_field_value(list, fields, fvalues, n_fields,
0N/A info->index, ovalue, info->primType);
0N/A n_fields_set++;
0N/A HPROF_ASSERT(n_fields_set <= n_fields);
0N/A break;
0N/A case INFO_PRIM_ARRAY_DATA:
0N/A default:
0N/A /* Should never see these */
0N/A HPROF_ASSERT(0);
0N/A break;
0N/A }
0N/A
0N/A index = info->next;
0N/A }
0N/A
0N/A /* Get constant pool data if we have any */
0N/A HPROF_ASSERT(cpool_count==stack_depth(cpool_values));
0N/A if ( cpool_count > 0 ) {
0N/A cpool = (ConstantPoolValue*)stack_element(cpool_values, 0);
0N/A }
0N/A io_heap_class_dump(cnum, sig, object_index, trace_serial_num,
0N/A super_index,
0N/A loader_object_index(env, loader_index),
0N/A signers_index, domain_index,
0N/A (jint)size, cpool_count, cpool, n_fields, fields, fvalues);
0N/A
0N/A stack_term(cpool_values);
0N/A if ( fvalues != NULL ) {
0N/A HPROF_FREE(fvalues);
0N/A }
0N/A}
0N/A
0N/A/* Walk all references for an ObjectIndex and construct the hprof INST dump. */
0N/Astatic void
0N/Adump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list)
0N/A{
0N/A jvmtiPrimitiveType primType;
0N/A SiteIndex site_index;
0N/A SerialNumber trace_serial_num;
0N/A RefIndex index;
0N/A ObjectIndex class_index;
0N/A jlong size;
0N/A ClassIndex cnum;
0N/A char *sig;
0N/A void *elements;
0N/A jint num_elements;
0N/A jint num_bytes;
0N/A ObjectIndex *values;
0N/A FieldInfo *fields;
0N/A jvalue *fvalues;
0N/A jint n_fields;
0N/A jboolean skip_fields;
0N/A jint n_fields_set;
0N/A ObjectKind kind;
0N/A TraceIndex trace_index;
0N/A jboolean is_array;
0N/A jboolean is_prim_array;
0N/A
0N/A HPROF_ASSERT(object_index!=0);
0N/A kind = object_get_kind(object_index);
0N/A if ( kind == OBJECT_CLASS ) {
0N/A return;
0N/A }
0N/A site_index = object_get_site(object_index);
0N/A HPROF_ASSERT(site_index!=0);
0N/A cnum = site_get_class_index(site_index);
0N/A HPROF_ASSERT(cnum!=0);
0N/A size = (jlong)object_get_size(object_index);
0N/A trace_index = site_get_trace_index(site_index);
0N/A HPROF_ASSERT(trace_index!=0);
0N/A trace_serial_num = trace_get_serial_number(trace_index);
0N/A sig = string_get(class_get_signature(cnum));
0N/A class_index = class_get_object_index(cnum);
0N/A
0N/A values = NULL;
0N/A elements = NULL;
0N/A num_elements = 0;
0N/A num_bytes = 0;
0N/A
0N/A n_fields = 0;
0N/A skip_fields = JNI_FALSE;
0N/A n_fields_set = 0;
0N/A fields = NULL;
0N/A fvalues = NULL;
0N/A
0N/A index = list;
0N/A
0N/A is_array = JNI_FALSE;
0N/A is_prim_array = JNI_FALSE;
0N/A
0N/A if ( sig[0] != JVM_SIGNATURE_ARRAY ) {
0N/A if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) {
0N/A /* Trouble getting all the fields, can't trust field index values */
0N/A skip_fields = JNI_TRUE;
0N/A /* It is assumed that the reason why we didn't get the fields
0N/A * was because the class is not prepared.
0N/A */
0N/A if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) {
0N/A if ( list != 0 ) {
0N/A dump_ref_list(list);
0N/A debug_message("Instance of unprepared class with refs: %s\n",
0N/A sig);
0N/A } else {
0N/A debug_message("Instance of unprepared class without refs: %s\n",
0N/A sig);
0N/A }
0N/A HPROF_ERROR(JNI_FALSE, "Big Trouble with unprepared class instances");
0N/A }
0N/A }
0N/A if ( n_fields > 0 ) {
0N/A fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue));
0N/A (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue));
0N/A }
0N/A } else {
0N/A is_array = JNI_TRUE;
0N/A if ( sig[0] != 0 && sigToPrimSize(sig+1) != 0 ) {
0N/A is_prim_array = JNI_TRUE;
0N/A }
0N/A }
0N/A
0N/A while ( index != 0 ) {
0N/A RefInfo *info;
0N/A jvalue ovalue;
0N/A static jvalue empty_value;
0N/A
0N/A info = get_info(index);
0N/A
0N/A /* Process reference objects, many not used right now. */
0N/A switch ( info->flavor ) {
0N/A case INFO_OBJECT_REF_DATA:
0N/A switch ( info->refKind ) {
0N/A case JVMTI_HEAP_REFERENCE_SIGNERS:
0N/A case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
0N/A case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
0N/A case JVMTI_HEAP_REFERENCE_INTERFACE:
0N/A case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
0N/A case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
0N/A /* Should never be seen on an instance dump */
0N/A HPROF_ASSERT(0);
0N/A break;
0N/A case JVMTI_HEAP_REFERENCE_FIELD:
0N/A if ( skip_fields == JNI_TRUE ) {
0N/A break;
0N/A }
0N/A HPROF_ASSERT(is_array!=JNI_TRUE);
0N/A ovalue = empty_value;
0N/A ovalue.i = info->object_index;
0N/A fill_in_field_value(list, fields, fvalues, n_fields,
0N/A info->index, ovalue, 0);
0N/A n_fields_set++;
0N/A HPROF_ASSERT(n_fields_set <= n_fields);
0N/A break;
0N/A case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
0N/A /* We get each object element one at a time. */
0N/A HPROF_ASSERT(is_array==JNI_TRUE);
0N/A HPROF_ASSERT(is_prim_array!=JNI_TRUE);
0N/A if ( num_elements <= info->index ) {
0N/A int nbytes;
0N/A
0N/A if ( values == NULL ) {
0N/A num_elements = info->index + 1;
0N/A nbytes = num_elements*(int)sizeof(ObjectIndex);
0N/A values = (ObjectIndex*)HPROF_MALLOC(nbytes);
0N/A (void)memset(values, 0, nbytes);
0N/A } else {
0N/A void *new_values;
0N/A int new_size;
0N/A int obytes;
0N/A
0N/A obytes = num_elements*(int)sizeof(ObjectIndex);
0N/A new_size = info->index + 1;
0N/A nbytes = new_size*(int)sizeof(ObjectIndex);
0N/A new_values = (void*)HPROF_MALLOC(nbytes);
0N/A (void)memcpy(new_values, values, obytes);
0N/A (void)memset(((char*)new_values)+obytes, 0,
0N/A nbytes-obytes);
0N/A HPROF_FREE(values);
0N/A num_elements = new_size;
0N/A values = new_values;
0N/A }
0N/A }
0N/A HPROF_ASSERT(values[info->index]==0);
0N/A values[info->index] = info->object_index;
0N/A break;
0N/A default:
0N/A /* Ignore, not needed */
0N/A break;
0N/A }
0N/A break;
0N/A case INFO_PRIM_FIELD_DATA:
0N/A if ( skip_fields == JNI_TRUE ) {
0N/A break;
0N/A }
0N/A HPROF_ASSERT(info->primType!=0);
0N/A HPROF_ASSERT(info->length==-1);
0N/A HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_FIELD);
0N/A HPROF_ASSERT(is_array!=JNI_TRUE);
0N/A ovalue = get_key_value(index);
0N/A fill_in_field_value(list, fields, fvalues, n_fields,
0N/A info->index, ovalue, info->primType);
0N/A n_fields_set++;
0N/A HPROF_ASSERT(n_fields_set <= n_fields);
0N/A break;
0N/A case INFO_PRIM_ARRAY_DATA:
0N/A /* Should only be one, and it's handled below */
0N/A HPROF_ASSERT(info->refKind==0);
0N/A /* We assert that nothing else was saved with this array */
0N/A HPROF_ASSERT(index==list&&info->next==0);
0N/A HPROF_ASSERT(is_array==JNI_TRUE);
0N/A HPROF_ASSERT(is_prim_array==JNI_TRUE);
0N/A primType = info->primType;
0N/A elements = get_key_elements(index, primType,
0N/A &num_elements, &num_bytes);
0N/A HPROF_ASSERT(info->length==num_elements);
0N/A size = num_bytes;
0N/A break;
0N/A default:
0N/A HPROF_ASSERT(0);
0N/A break;
0N/A }
0N/A index = info->next;
0N/A }
0N/A
0N/A if ( is_array == JNI_TRUE ) {
0N/A if ( is_prim_array == JNI_TRUE ) {
0N/A HPROF_ASSERT(values==NULL);
0N/A io_heap_prim_array(object_index, trace_serial_num,
0N/A (jint)size, num_elements, sig, elements);
0N/A } else {
0N/A HPROF_ASSERT(elements==NULL);
0N/A io_heap_object_array(object_index, trace_serial_num,
0N/A (jint)size, num_elements, sig, values, class_index);
0N/A }
0N/A } else {
0N/A io_heap_instance_dump(cnum, object_index, trace_serial_num,
0N/A class_index, (jint)size, sig, fields, fvalues, n_fields);
0N/A }
0N/A if ( values != NULL ) {
0N/A HPROF_FREE(values);
0N/A }
0N/A if ( fvalues != NULL ) {
0N/A HPROF_FREE(fvalues);
0N/A }
0N/A if ( elements != NULL ) {
0N/A /* Do NOT free elements, it's a key in the table, leave it be */
0N/A }
0N/A}
0N/A
0N/A/* External interfaces. */
0N/A
0N/Avoid
0N/Areference_init(void)
0N/A{
0N/A HPROF_ASSERT(gdata->reference_table==NULL);
0N/A gdata->reference_table = table_initialize("Ref", 2048, 4096, 0,
0N/A (int)sizeof(RefInfo));
0N/A}
0N/A
0N/A/* Save away a reference to an object */
0N/ARefIndex
0N/Areference_obj(RefIndex next, jvmtiHeapReferenceKind refKind,
0N/A ObjectIndex object_index, jint index, jint length)
0N/A{
0N/A static RefInfo empty_info;
0N/A RefIndex entry;
0N/A RefInfo info;
0N/A
0N/A info = empty_info;
0N/A info.flavor = INFO_OBJECT_REF_DATA;
0N/A info.refKind = refKind;
0N/A info.object_index = object_index;
0N/A info.index = index;
0N/A info.length = length;
0N/A info.next = next;
0N/A entry = table_create_entry(gdata->reference_table, NULL, 0, (void*)&info);
0N/A return entry;
0N/A}
0N/A
0N/A/* Save away some primitive field data */
0N/ARefIndex
0N/Areference_prim_field(RefIndex next, jvmtiHeapReferenceKind refKind,
0N/A jvmtiPrimitiveType primType, jvalue field_value, jint field_index)
0N/A{
0N/A static RefInfo empty_info;
0N/A RefIndex entry;
0N/A RefInfo info;
0N/A
0N/A HPROF_ASSERT(primType==JVMTI_PRIMITIVE_TYPE_BOOLEAN?(field_value.b==1||field_value.b==0):1);
0N/A
0N/A info = empty_info;
0N/A info.flavor = INFO_PRIM_FIELD_DATA;
0N/A info.refKind = refKind;
0N/A info.primType = primType;
0N/A info.index = field_index;
0N/A info.length = -1;
0N/A info.next = next;
0N/A entry = table_create_entry(gdata->reference_table,
0N/A (void*)&field_value, (int)sizeof(jvalue), (void*)&info);
0N/A return entry;
0N/A}
0N/A
0N/A/* Save away some primitive array data */
0N/ARefIndex
0N/Areference_prim_array(RefIndex next, jvmtiPrimitiveType primType,
0N/A const void *elements, jint elementCount)
0N/A{
0N/A static RefInfo empty_info;
0N/A RefIndex entry;
0N/A RefInfo info;
0N/A
0N/A HPROF_ASSERT(next == 0);
0N/A HPROF_ASSERT(elementCount >= 0);
0N/A HPROF_ASSERT(elements != NULL);
0N/A
0N/A info = empty_info;
0N/A info.flavor = INFO_PRIM_ARRAY_DATA;
0N/A info.refKind = 0;
0N/A info.primType = primType;
0N/A info.index = 0;
0N/A info.length = elementCount;
0N/A info.next = next;
0N/A entry = table_create_entry(gdata->reference_table, (void*)elements,
0N/A elementCount * get_prim_size(primType), (void*)&info);
0N/A return entry;
0N/A}
0N/A
0N/Avoid
0N/Areference_cleanup(void)
0N/A{
0N/A if ( gdata->reference_table == NULL ) {
0N/A return;
0N/A }
0N/A table_cleanup(gdata->reference_table, NULL, NULL);
0N/A gdata->reference_table = NULL;
0N/A}
0N/A
0N/Avoid
0N/Areference_dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list)
0N/A{
0N/A dump_instance(env, object_index, list);
0N/A}
0N/A
0N/Avoid
0N/Areference_dump_class(JNIEnv *env, ObjectIndex object_index, RefIndex list)
0N/A{
0N/A dump_class_and_supers(env, object_index, list);
0N/A}