jdk/src/jdk.hprof.agent/share/native/libhprof/hprof_reference.c
changeset 32249 ba2c9c7773b6
parent 32248 13967da712ff
parent 32247 9f3dd33507b9
child 32253 637b00638ed6
equal deleted inserted replaced
32248:13967da712ff 32249:ba2c9c7773b6
     1 /*
       
     2  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  *   - Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer.
       
    10  *
       
    11  *   - Redistributions in binary form must reproduce the above copyright
       
    12  *     notice, this list of conditions and the following disclaimer in the
       
    13  *     documentation and/or other materials provided with the distribution.
       
    14  *
       
    15  *   - Neither the name of Oracle nor the names of its
       
    16  *     contributors may be used to endorse or promote products derived
       
    17  *     from this software without specific prior written permission.
       
    18  *
       
    19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       
    20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
       
    21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
       
    23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       
    27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
       
    28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    30  */
       
    31 
       
    32 /*
       
    33  * This source code is provided to illustrate the usage of a given feature
       
    34  * or technique and has been deliberately simplified. Additional steps
       
    35  * required for a production-quality application, such as security checks,
       
    36  * input validation and proper error handling, might not be present in
       
    37  * this sample code.
       
    38  */
       
    39 
       
    40 
       
    41 /* Object references table (used in hprof_object.c). */
       
    42 
       
    43 /*
       
    44  * This table is used by the object table to store object reference
       
    45  *   and primitive data information obtained from iterations over the
       
    46  *   heap (see hprof_site.c).
       
    47  *
       
    48  * Most of these table entries have no Key, but the key is used to store
       
    49  *   the primitive array and primitive field jvalue. None of these entries
       
    50  *   are ever looked up, there will be no hash table, use of the
       
    51  *   LookupTable was just an easy way to handle a unbounded table of
       
    52  *   entries. The object table (see hprof_object.c) will completely
       
    53  *   free this reference table after each heap dump or after processing the
       
    54  *   references and primitive data.
       
    55  *
       
    56  * The hprof format required this accumulation of all heap iteration
       
    57  *   references and primitive data from objects in order to compose an
       
    58  *   hprof records for it.
       
    59  *
       
    60  * This file contains detailed understandings of how an hprof CLASS
       
    61  *   and INSTANCE dump is constructed, most of this is derived from the
       
    62  *   original hprof code, but some has been derived by reading the HAT
       
    63  *   code that accepts this format.
       
    64  *
       
    65  */
       
    66 
       
    67 #include "hprof.h"
       
    68 
       
    69 /* The flavor of data being saved in the RefInfo */
       
    70 enum {
       
    71     INFO_OBJECT_REF_DATA    = 1,
       
    72     INFO_PRIM_FIELD_DATA    = 2,
       
    73     INFO_PRIM_ARRAY_DATA    = 3
       
    74 };
       
    75 
       
    76 /* Reference information, object reference or primitive data information */
       
    77 typedef struct RefInfo {
       
    78     ObjectIndex object_index; /* If an object reference, the referree index */
       
    79     jint        index;        /* If array or field, array or field index */
       
    80     jint        length;       /* If array the element count, if not -1 */
       
    81     RefIndex    next;         /* The next table element */
       
    82     unsigned    flavor   : 8; /* INFO_*, flavor of RefInfo */
       
    83     unsigned    refKind  : 8; /* The kind of reference */
       
    84     unsigned    primType : 8; /* If primitive data involved, it's type */
       
    85 } RefInfo;
       
    86 
       
    87 /* Private internal functions. */
       
    88 
       
    89 /* Get the RefInfo structure from an entry */
       
    90 static RefInfo *
       
    91 get_info(RefIndex index)
       
    92 {
       
    93     RefInfo *info;
       
    94 
       
    95     info = (RefInfo*)table_get_info(gdata->reference_table, index);
       
    96     return info;
       
    97 }
       
    98 
       
    99 /* Get a jvalue that was stored as the key. */
       
   100 static jvalue
       
   101 get_key_value(RefIndex index)
       
   102 {
       
   103     void  *key;
       
   104     int    len;
       
   105     jvalue value;
       
   106     static jvalue empty_value;
       
   107 
       
   108     key = NULL;
       
   109     table_get_key(gdata->reference_table, index, &key, &len);
       
   110     HPROF_ASSERT(key!=NULL);
       
   111     HPROF_ASSERT(len==(int)sizeof(jvalue));
       
   112     if ( key != NULL ) {
       
   113         (void)memcpy(&value, key, (int)sizeof(jvalue));
       
   114     } else {
       
   115         value = empty_value;
       
   116     }
       
   117     return value;
       
   118 }
       
   119 
       
   120 /* Get size of a primitive type */
       
   121 static jint
       
   122 get_prim_size(jvmtiPrimitiveType primType)
       
   123 {
       
   124     jint size;
       
   125 
       
   126     switch ( primType ) {
       
   127         case JVMTI_PRIMITIVE_TYPE_BOOLEAN:
       
   128             size = (jint)sizeof(jboolean);
       
   129             break;
       
   130         case JVMTI_PRIMITIVE_TYPE_BYTE:
       
   131             size = (jint)sizeof(jbyte);
       
   132             break;
       
   133         case JVMTI_PRIMITIVE_TYPE_CHAR:
       
   134             size = (jint)sizeof(jchar);
       
   135             break;
       
   136         case JVMTI_PRIMITIVE_TYPE_SHORT:
       
   137             size = (jint)sizeof(jshort);
       
   138             break;
       
   139         case JVMTI_PRIMITIVE_TYPE_INT:
       
   140             size = (jint)sizeof(jint);
       
   141             break;
       
   142         case JVMTI_PRIMITIVE_TYPE_FLOAT:
       
   143             size = (jint)sizeof(jfloat);
       
   144             break;
       
   145         case JVMTI_PRIMITIVE_TYPE_LONG:
       
   146             size = (jint)sizeof(jlong);
       
   147             break;
       
   148         case JVMTI_PRIMITIVE_TYPE_DOUBLE:
       
   149             size = (jint)sizeof(jdouble);
       
   150             break;
       
   151         default:
       
   152             HPROF_ASSERT(0);
       
   153             size = 1;
       
   154             break;
       
   155     }
       
   156     return size;
       
   157 }
       
   158 
       
   159 /* Get a void* elements array that was stored as the key. */
       
   160 static void *
       
   161 get_key_elements(RefIndex index, jvmtiPrimitiveType primType,
       
   162                  jint *nelements, jint *nbytes)
       
   163 {
       
   164     void  *key;
       
   165     jint   byteLen;
       
   166 
       
   167     HPROF_ASSERT(nelements!=NULL);
       
   168     HPROF_ASSERT(nbytes!=NULL);
       
   169 
       
   170     table_get_key(gdata->reference_table, index, &key, &byteLen);
       
   171     HPROF_ASSERT(byteLen>=0);
       
   172     HPROF_ASSERT(byteLen!=0?key!=NULL:key==NULL);
       
   173     *nbytes      = byteLen;
       
   174     *nelements   = byteLen / get_prim_size(primType);
       
   175     return key;
       
   176 }
       
   177 
       
   178 /* Dump a RefInfo* structure */
       
   179 static void
       
   180 dump_ref_info(RefInfo *info)
       
   181 {
       
   182     debug_message("[%d]: flavor=%d"
       
   183                           ", refKind=%d"
       
   184                           ", primType=%d"
       
   185                           ", object_index=0x%x"
       
   186                           ", length=%d"
       
   187                           ", next=0x%x"
       
   188                           "\n",
       
   189             info->index,
       
   190             info->flavor,
       
   191             info->refKind,
       
   192             info->primType,
       
   193             info->object_index,
       
   194             info->length,
       
   195             info->next);
       
   196 }
       
   197 
       
   198 /* Dump a RefIndex list */
       
   199 static void
       
   200 dump_ref_list(RefIndex list)
       
   201 {
       
   202     RefInfo *info;
       
   203     RefIndex index;
       
   204 
       
   205     debug_message("\nFOLLOW REFERENCES RETURNED:\n");
       
   206     index = list;
       
   207     while ( index != 0 ) {
       
   208         info = get_info(index);
       
   209         dump_ref_info(info);
       
   210         index = info->next;
       
   211     }
       
   212 }
       
   213 
       
   214 /* Dump information about a field and what ref data we had on it */
       
   215 static void
       
   216 dump_field(FieldInfo *fields, jvalue *fvalues, int n_fields,
       
   217                 jint index, jvalue value, jvmtiPrimitiveType primType)
       
   218 {
       
   219     ClassIndex  cnum;
       
   220     StringIndex name;
       
   221     StringIndex sig;
       
   222 
       
   223     cnum = fields[index].cnum;
       
   224     name = fields[index].name_index;
       
   225     sig  = fields[index].sig_index;
       
   226     debug_message("[%d] %s \"%s\" \"%s\"",
       
   227           index,
       
   228           cnum!=0?string_get(class_get_signature(cnum)):"?",
       
   229           name!=0?string_get(name):"?",
       
   230           sig!=0?string_get(sig):"?");
       
   231     if ( fields[index].primType!=0 || fields[index].primType!=primType ) {
       
   232         debug_message(" (primType=%d(%c)",
       
   233           fields[index].primType,
       
   234           primTypeToSigChar(fields[index].primType));
       
   235         if ( primType != fields[index].primType ) {
       
   236             debug_message(", got %d(%c)",
       
   237               primType,
       
   238               primTypeToSigChar(primType));
       
   239         }
       
   240         debug_message(")");
       
   241     } else {
       
   242         debug_message("(ty=OBJ)");
       
   243     }
       
   244     if ( value.j != (jlong)0 || fvalues[index].j != (jlong)0 ) {
       
   245         debug_message(" val=[0x%08x,0x%08x] or [0x%08x,0x%08x]",
       
   246             jlong_high(value.j), jlong_low(value.j),
       
   247             jlong_high(fvalues[index].j), jlong_low(fvalues[index].j));
       
   248     }
       
   249     debug_message("\n");
       
   250 }
       
   251 
       
   252 /* Dump all the fields of interest */
       
   253 static void
       
   254 dump_fields(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields)
       
   255 {
       
   256     int i;
       
   257 
       
   258     debug_message("\nHPROF LIST OF ALL FIELDS:\n");
       
   259     for ( i = 0 ; i < n_fields ; i++ ) {
       
   260         if ( fields[i].name_index != 0 ) {
       
   261             dump_field(fields, fvalues, n_fields, i, fvalues[i], fields[i].primType);
       
   262         }
       
   263     }
       
   264     dump_ref_list(list);
       
   265 }
       
   266 
       
   267 /* Verify field data */
       
   268 static void
       
   269 verify_field(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields,
       
   270                 jint index, jvalue value, jvmtiPrimitiveType primType)
       
   271 {
       
   272     HPROF_ASSERT(fvalues != NULL);
       
   273     HPROF_ASSERT(n_fields > 0);
       
   274     HPROF_ASSERT(index < n_fields);
       
   275     HPROF_ASSERT(index >= 0 );
       
   276     if ( primType!=fields[index].primType ) {
       
   277         dump_fields(list, fields, fvalues, n_fields);
       
   278         debug_message("\nPROBLEM WITH:\n");
       
   279         dump_field(fields, fvalues, n_fields, index, value, primType);
       
   280         debug_message("\n");
       
   281         HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data");
       
   282     }
       
   283     if ( primType == JVMTI_PRIMITIVE_TYPE_BOOLEAN &&
       
   284          ( value.b != 1 && value.b != 0 ) ) {
       
   285         dump_fields(list, fields, fvalues, n_fields);
       
   286         debug_message("\nPROBLEM WITH:\n");
       
   287         dump_field(fields, fvalues, n_fields, index, value, primType);
       
   288         debug_message("\n");
       
   289         HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data");
       
   290     }
       
   291 }
       
   292 
       
   293 /* Fill in a field value, making sure the index is safe */
       
   294 static void
       
   295 fill_in_field_value(RefIndex list, FieldInfo *fields, jvalue *fvalues,
       
   296                     int n_fields, jint index, jvalue value,
       
   297                     jvmtiPrimitiveType primType)
       
   298 {
       
   299     HPROF_ASSERT(fvalues != NULL);
       
   300     HPROF_ASSERT(n_fields > 0);
       
   301     HPROF_ASSERT(index < n_fields);
       
   302     HPROF_ASSERT(index >= 0 );
       
   303     HPROF_ASSERT(fvalues[index].j==(jlong)0);
       
   304     verify_field(list, fields, fvalues, n_fields, index, value, primType);
       
   305     if (index >= 0 && index < n_fields) {
       
   306         fvalues[index] = value;
       
   307     }
       
   308 }
       
   309 
       
   310 /* Walk all references for an ObjectIndex and construct the hprof CLASS dump. */
       
   311 static void
       
   312 dump_class_and_supers(JNIEnv *env, ObjectIndex object_index, RefIndex list)
       
   313 {
       
   314     SiteIndex    site_index;
       
   315     SerialNumber trace_serial_num;
       
   316     RefIndex     index;
       
   317     ClassIndex   super_cnum;
       
   318     ObjectIndex  super_index;
       
   319     LoaderIndex  loader_index;
       
   320     ObjectIndex  signers_index;
       
   321     ObjectIndex  domain_index;
       
   322     FieldInfo   *fields;
       
   323     jvalue      *fvalues;
       
   324     jint         n_fields;
       
   325     jboolean     skip_fields;
       
   326     jint         n_fields_set;
       
   327     jlong        size;
       
   328     ClassIndex   cnum;
       
   329     char        *sig;
       
   330     ObjectKind   kind;
       
   331     TraceIndex   trace_index;
       
   332     Stack       *cpool_values;
       
   333     ConstantPoolValue *cpool;
       
   334     jint         cpool_count;
       
   335 
       
   336     HPROF_ASSERT(object_index!=0);
       
   337     kind        = object_get_kind(object_index);
       
   338     if ( kind != OBJECT_CLASS ) {
       
   339         return;
       
   340     }
       
   341     site_index         = object_get_site(object_index);
       
   342     HPROF_ASSERT(site_index!=0);
       
   343     cnum        = site_get_class_index(site_index);
       
   344     HPROF_ASSERT(cnum!=0);
       
   345     if ( class_get_status(cnum) & CLASS_DUMPED ) {
       
   346         return;
       
   347     }
       
   348     class_add_status(cnum, CLASS_DUMPED);
       
   349     size        = (jlong)object_get_size(object_index);
       
   350 
       
   351     super_index = 0;
       
   352     super_cnum  = class_get_super(cnum);
       
   353     if ( super_cnum != 0 ) {
       
   354         super_index  = class_get_object_index(super_cnum);
       
   355         if ( super_index != 0 ) {
       
   356             dump_class_and_supers(env, super_index,
       
   357                         object_get_references(super_index));
       
   358         }
       
   359     }
       
   360 
       
   361     trace_index      = site_get_trace_index(site_index);
       
   362     HPROF_ASSERT(trace_index!=0);
       
   363     trace_serial_num = trace_get_serial_number(trace_index);
       
   364     sig              = string_get(class_get_signature(cnum));
       
   365     loader_index     = class_get_loader(cnum);
       
   366     signers_index    = 0;
       
   367     domain_index     = 0;
       
   368 
       
   369     /* Get field information */
       
   370     n_fields     = 0;
       
   371     skip_fields  = JNI_FALSE;
       
   372     n_fields_set = 0;
       
   373     fields       = NULL;
       
   374     fvalues      = NULL;
       
   375     if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) {
       
   376         /* Problems getting all the fields, can't trust field index values */
       
   377         skip_fields = JNI_TRUE;
       
   378         /* Class with no references at all? (ok to be unprepared if list==0?) */
       
   379         if ( list != 0 ) {
       
   380             /* It is assumed that the reason why we didn't get the fields
       
   381              *     was because the class is not prepared.
       
   382              */
       
   383             if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) {
       
   384                 dump_ref_list(list);
       
   385                 debug_message("Unprepared class with references: %s\n",
       
   386                                sig);
       
   387             }
       
   388             HPROF_ERROR(JNI_FALSE, "Trouble with unprepared classes");
       
   389         }
       
   390         /* Why would an unprepared class contain references? */
       
   391     }
       
   392     if ( n_fields > 0 ) {
       
   393         fvalues      = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue));
       
   394         (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue));
       
   395     }
       
   396 
       
   397     /* We use a Stack just because it will automatically expand as needed */
       
   398     cpool_values = stack_init(16, 16, sizeof(ConstantPoolValue));
       
   399     cpool = NULL;
       
   400     cpool_count = 0;
       
   401 
       
   402     index      = list;
       
   403     while ( index != 0 ) {
       
   404         RefInfo    *info;
       
   405         jvalue      ovalue;
       
   406         static jvalue empty_value;
       
   407 
       
   408         info = get_info(index);
       
   409 
       
   410         switch ( info->flavor ) {
       
   411             case INFO_OBJECT_REF_DATA:
       
   412                 switch ( info->refKind ) {
       
   413                     case JVMTI_HEAP_REFERENCE_FIELD:
       
   414                     case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
       
   415                         /* Should never be seen on a class dump */
       
   416                         HPROF_ASSERT(0);
       
   417                         break;
       
   418                     case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
       
   419                         if ( skip_fields == JNI_TRUE ) {
       
   420                             break;
       
   421                         }
       
   422                         ovalue   = empty_value;
       
   423                         ovalue.i = info->object_index;
       
   424                         fill_in_field_value(list, fields, fvalues, n_fields,
       
   425                                         info->index, ovalue, 0);
       
   426                         n_fields_set++;
       
   427                         HPROF_ASSERT(n_fields_set <= n_fields);
       
   428                         break;
       
   429                     case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: {
       
   430                         ConstantPoolValue cpv;
       
   431                         ObjectIndex       cp_object_index;
       
   432                         SiteIndex         cp_site_index;
       
   433                         ClassIndex        cp_cnum;
       
   434 
       
   435                         cp_object_index = info->object_index;
       
   436                         HPROF_ASSERT(cp_object_index!=0);
       
   437                         cp_site_index = object_get_site(cp_object_index);
       
   438                         HPROF_ASSERT(cp_site_index!=0);
       
   439                         cp_cnum = site_get_class_index(cp_site_index);
       
   440                         cpv.constant_pool_index = info->index;
       
   441                         cpv.sig_index = class_get_signature(cp_cnum);
       
   442                         cpv.value.i = cp_object_index;
       
   443                         stack_push(cpool_values, (void*)&cpv);
       
   444                         cpool_count++;
       
   445                         break;
       
   446                         }
       
   447                     case JVMTI_HEAP_REFERENCE_SIGNERS:
       
   448                         signers_index = info->object_index;
       
   449                         break;
       
   450                     case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
       
   451                         domain_index = info->object_index;
       
   452                         break;
       
   453                     case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
       
   454                     case JVMTI_HEAP_REFERENCE_INTERFACE:
       
   455                     default:
       
   456                         /* Ignore, not needed */
       
   457                         break;
       
   458                 }
       
   459                 break;
       
   460             case INFO_PRIM_FIELD_DATA:
       
   461                 if ( skip_fields == JNI_TRUE ) {
       
   462                     break;
       
   463                 }
       
   464                 HPROF_ASSERT(info->primType!=0);
       
   465                 HPROF_ASSERT(info->length==-1);
       
   466                 HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_STATIC_FIELD);
       
   467                 ovalue = get_key_value(index);
       
   468                 fill_in_field_value(list, fields, fvalues, n_fields,
       
   469                                     info->index, ovalue, info->primType);
       
   470                 n_fields_set++;
       
   471                 HPROF_ASSERT(n_fields_set <= n_fields);
       
   472                 break;
       
   473             case INFO_PRIM_ARRAY_DATA:
       
   474             default:
       
   475                 /* Should never see these */
       
   476                 HPROF_ASSERT(0);
       
   477                 break;
       
   478         }
       
   479 
       
   480         index = info->next;
       
   481     }
       
   482 
       
   483     /* Get constant pool data if we have any */
       
   484     HPROF_ASSERT(cpool_count==stack_depth(cpool_values));
       
   485     if ( cpool_count > 0 ) {
       
   486         cpool = (ConstantPoolValue*)stack_element(cpool_values, 0);
       
   487     }
       
   488     io_heap_class_dump(cnum, sig, object_index, trace_serial_num,
       
   489             super_index,
       
   490             loader_object_index(env, loader_index),
       
   491             signers_index, domain_index,
       
   492             (jint)size, cpool_count, cpool, n_fields, fields, fvalues);
       
   493 
       
   494     stack_term(cpool_values);
       
   495     if ( fvalues != NULL ) {
       
   496         HPROF_FREE(fvalues);
       
   497     }
       
   498 }
       
   499 
       
   500 /* Walk all references for an ObjectIndex and construct the hprof INST dump. */
       
   501 static void
       
   502 dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list)
       
   503 {
       
   504     jvmtiPrimitiveType primType;
       
   505     SiteIndex    site_index;
       
   506     SerialNumber trace_serial_num;
       
   507     RefIndex     index;
       
   508     ObjectIndex  class_index;
       
   509     jlong        size;
       
   510     ClassIndex   cnum;
       
   511     char        *sig;
       
   512     void        *elements;
       
   513     jint         num_elements;
       
   514     jint         num_bytes;
       
   515     ObjectIndex *values;
       
   516     FieldInfo   *fields;
       
   517     jvalue      *fvalues;
       
   518     jint         n_fields;
       
   519     jboolean     skip_fields;
       
   520     jint         n_fields_set;
       
   521     ObjectKind   kind;
       
   522     TraceIndex   trace_index;
       
   523     jboolean     is_array;
       
   524     jboolean     is_prim_array;
       
   525 
       
   526     HPROF_ASSERT(object_index!=0);
       
   527     kind        = object_get_kind(object_index);
       
   528     if ( kind == OBJECT_CLASS ) {
       
   529         return;
       
   530     }
       
   531     site_index       = object_get_site(object_index);
       
   532     HPROF_ASSERT(site_index!=0);
       
   533     cnum             = site_get_class_index(site_index);
       
   534     HPROF_ASSERT(cnum!=0);
       
   535     size             = (jlong)object_get_size(object_index);
       
   536     trace_index      = site_get_trace_index(site_index);
       
   537     HPROF_ASSERT(trace_index!=0);
       
   538     trace_serial_num = trace_get_serial_number(trace_index);
       
   539     sig              = string_get(class_get_signature(cnum));
       
   540     class_index      = class_get_object_index(cnum);
       
   541 
       
   542     values       = NULL;
       
   543     elements     = NULL;
       
   544     num_elements = 0;
       
   545     num_bytes    = 0;
       
   546 
       
   547     n_fields     = 0;
       
   548     skip_fields  = JNI_FALSE;
       
   549     n_fields_set = 0;
       
   550     fields       = NULL;
       
   551     fvalues      = NULL;
       
   552 
       
   553     index      = list;
       
   554 
       
   555     is_array      = JNI_FALSE;
       
   556     is_prim_array = JNI_FALSE;
       
   557 
       
   558     if ( sig[0] != JVM_SIGNATURE_ARRAY ) {
       
   559         if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) {
       
   560             /* Trouble getting all the fields, can't trust field index values */
       
   561             skip_fields = JNI_TRUE;
       
   562             /* It is assumed that the reason why we didn't get the fields
       
   563              *     was because the class is not prepared.
       
   564              */
       
   565             if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) {
       
   566                 if ( list != 0 ) {
       
   567                     dump_ref_list(list);
       
   568                     debug_message("Instance of unprepared class with refs: %s\n",
       
   569                                    sig);
       
   570                 } else {
       
   571                     debug_message("Instance of unprepared class without refs: %s\n",
       
   572                                    sig);
       
   573                 }
       
   574                 HPROF_ERROR(JNI_FALSE, "Big Trouble with unprepared class instances");
       
   575             }
       
   576         }
       
   577         if ( n_fields > 0 ) {
       
   578             fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue));
       
   579             (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue));
       
   580         }
       
   581     } else {
       
   582         is_array = JNI_TRUE;
       
   583         if ( sig[0] != 0 && sigToPrimSize(sig+1) != 0 ) {
       
   584             is_prim_array = JNI_TRUE;
       
   585         }
       
   586     }
       
   587 
       
   588     while ( index != 0 ) {
       
   589         RefInfo *info;
       
   590         jvalue   ovalue;
       
   591         static jvalue empty_value;
       
   592 
       
   593         info = get_info(index);
       
   594 
       
   595         /* Process reference objects, many not used right now. */
       
   596         switch ( info->flavor ) {
       
   597             case INFO_OBJECT_REF_DATA:
       
   598                 switch ( info->refKind ) {
       
   599                     case JVMTI_HEAP_REFERENCE_SIGNERS:
       
   600                     case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
       
   601                     case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
       
   602                     case JVMTI_HEAP_REFERENCE_INTERFACE:
       
   603                     case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
       
   604                     case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
       
   605                         /* Should never be seen on an instance dump */
       
   606                         HPROF_ASSERT(0);
       
   607                         break;
       
   608                     case JVMTI_HEAP_REFERENCE_FIELD:
       
   609                         if ( skip_fields == JNI_TRUE ) {
       
   610                             break;
       
   611                         }
       
   612                         HPROF_ASSERT(is_array!=JNI_TRUE);
       
   613                         ovalue   = empty_value;
       
   614                         ovalue.i = info->object_index;
       
   615                         fill_in_field_value(list, fields, fvalues, n_fields,
       
   616                                         info->index, ovalue, 0);
       
   617                         n_fields_set++;
       
   618                         HPROF_ASSERT(n_fields_set <= n_fields);
       
   619                         break;
       
   620                     case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
       
   621                         /* We get each object element one at a time.  */
       
   622                         HPROF_ASSERT(is_array==JNI_TRUE);
       
   623                         HPROF_ASSERT(is_prim_array!=JNI_TRUE);
       
   624                         if ( num_elements <= info->index ) {
       
   625                             int nbytes;
       
   626 
       
   627                             if ( values == NULL ) {
       
   628                                 num_elements = info->index + 1;
       
   629                                 nbytes = num_elements*(int)sizeof(ObjectIndex);
       
   630                                 values = (ObjectIndex*)HPROF_MALLOC(nbytes);
       
   631                                 (void)memset(values, 0, nbytes);
       
   632                             } else {
       
   633                                 void *new_values;
       
   634                                 int   new_size;
       
   635                                 int   obytes;
       
   636 
       
   637                                 obytes = num_elements*(int)sizeof(ObjectIndex);
       
   638                                 new_size = info->index + 1;
       
   639                                 nbytes = new_size*(int)sizeof(ObjectIndex);
       
   640                                 new_values = (void*)HPROF_MALLOC(nbytes);
       
   641                                 (void)memcpy(new_values, values, obytes);
       
   642                                 (void)memset(((char*)new_values)+obytes, 0,
       
   643                                                         nbytes-obytes);
       
   644                                 HPROF_FREE(values);
       
   645                                 num_elements = new_size;
       
   646                                 values =  new_values;
       
   647                             }
       
   648                         }
       
   649                         HPROF_ASSERT(values[info->index]==0);
       
   650                         values[info->index] = info->object_index;
       
   651                         break;
       
   652                     default:
       
   653                         /* Ignore, not needed */
       
   654                         break;
       
   655                 }
       
   656                 break;
       
   657             case INFO_PRIM_FIELD_DATA:
       
   658                 if ( skip_fields == JNI_TRUE ) {
       
   659                     break;
       
   660                 }
       
   661                 HPROF_ASSERT(info->primType!=0);
       
   662                 HPROF_ASSERT(info->length==-1);
       
   663                 HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_FIELD);
       
   664                 HPROF_ASSERT(is_array!=JNI_TRUE);
       
   665                 ovalue = get_key_value(index);
       
   666                 fill_in_field_value(list, fields, fvalues, n_fields,
       
   667                                     info->index, ovalue, info->primType);
       
   668                 n_fields_set++;
       
   669                 HPROF_ASSERT(n_fields_set <= n_fields);
       
   670                 break;
       
   671             case INFO_PRIM_ARRAY_DATA:
       
   672                 /* Should only be one, and it's handled below */
       
   673                 HPROF_ASSERT(info->refKind==0);
       
   674                 /* We assert that nothing else was saved with this array */
       
   675                 HPROF_ASSERT(index==list&&info->next==0);
       
   676                 HPROF_ASSERT(is_array==JNI_TRUE);
       
   677                 HPROF_ASSERT(is_prim_array==JNI_TRUE);
       
   678                 primType = info->primType;
       
   679                 elements = get_key_elements(index, primType,
       
   680                                             &num_elements, &num_bytes);
       
   681                 HPROF_ASSERT(info->length==num_elements);
       
   682                 size = num_bytes;
       
   683                 break;
       
   684             default:
       
   685                 HPROF_ASSERT(0);
       
   686                 break;
       
   687         }
       
   688         index = info->next;
       
   689     }
       
   690 
       
   691     if ( is_array == JNI_TRUE ) {
       
   692         if ( is_prim_array == JNI_TRUE ) {
       
   693             HPROF_ASSERT(values==NULL);
       
   694             io_heap_prim_array(object_index, trace_serial_num,
       
   695                     (jint)size, num_elements, sig, elements);
       
   696         } else {
       
   697             HPROF_ASSERT(elements==NULL);
       
   698             io_heap_object_array(object_index, trace_serial_num,
       
   699                     (jint)size, num_elements, sig, values, class_index);
       
   700         }
       
   701     } else {
       
   702         io_heap_instance_dump(cnum, object_index, trace_serial_num,
       
   703                     class_index, (jint)size, sig, fields, fvalues, n_fields);
       
   704     }
       
   705     if ( values != NULL ) {
       
   706         HPROF_FREE(values);
       
   707     }
       
   708     if ( fvalues != NULL ) {
       
   709         HPROF_FREE(fvalues);
       
   710     }
       
   711     if ( elements != NULL ) {
       
   712         /* Do NOT free elements, it's a key in the table, leave it be */
       
   713     }
       
   714 }
       
   715 
       
   716 /* External interfaces. */
       
   717 
       
   718 void
       
   719 reference_init(void)
       
   720 {
       
   721     HPROF_ASSERT(gdata->reference_table==NULL);
       
   722     gdata->reference_table = table_initialize("Ref", 2048, 4096, 0,
       
   723                             (int)sizeof(RefInfo));
       
   724 }
       
   725 
       
   726 /* Save away a reference to an object */
       
   727 RefIndex
       
   728 reference_obj(RefIndex next, jvmtiHeapReferenceKind refKind,
       
   729               ObjectIndex object_index, jint index, jint length)
       
   730 {
       
   731     static RefInfo  empty_info;
       
   732     RefIndex        entry;
       
   733     RefInfo         info;
       
   734 
       
   735     info                = empty_info;
       
   736     info.flavor         = INFO_OBJECT_REF_DATA;
       
   737     info.refKind        = refKind;
       
   738     info.object_index   = object_index;
       
   739     info.index          = index;
       
   740     info.length         = length;
       
   741     info.next           = next;
       
   742     entry = table_create_entry(gdata->reference_table, NULL, 0, (void*)&info);
       
   743     return entry;
       
   744 }
       
   745 
       
   746 /* Save away some primitive field data */
       
   747 RefIndex
       
   748 reference_prim_field(RefIndex next, jvmtiHeapReferenceKind refKind,
       
   749               jvmtiPrimitiveType primType, jvalue field_value, jint field_index)
       
   750 {
       
   751     static RefInfo  empty_info;
       
   752     RefIndex        entry;
       
   753     RefInfo         info;
       
   754 
       
   755     HPROF_ASSERT(primType==JVMTI_PRIMITIVE_TYPE_BOOLEAN?(field_value.b==1||field_value.b==0):1);
       
   756 
       
   757     info                = empty_info;
       
   758     info.flavor         = INFO_PRIM_FIELD_DATA;
       
   759     info.refKind        = refKind;
       
   760     info.primType       = primType;
       
   761     info.index          = field_index;
       
   762     info.length         = -1;
       
   763     info.next           = next;
       
   764     entry = table_create_entry(gdata->reference_table,
       
   765                 (void*)&field_value, (int)sizeof(jvalue), (void*)&info);
       
   766     return entry;
       
   767 }
       
   768 
       
   769 /* Save away some primitive array data */
       
   770 RefIndex
       
   771 reference_prim_array(RefIndex next, jvmtiPrimitiveType primType,
       
   772               const void *elements, jint elementCount)
       
   773 {
       
   774     static RefInfo  empty_info;
       
   775     RefIndex        entry;
       
   776     RefInfo         info;
       
   777 
       
   778     HPROF_ASSERT(next == 0);
       
   779     HPROF_ASSERT(elementCount >= 0);
       
   780     HPROF_ASSERT(elements != NULL);
       
   781 
       
   782     info                = empty_info;
       
   783     info.flavor         = INFO_PRIM_ARRAY_DATA;
       
   784     info.refKind        = 0;
       
   785     info.primType       = primType;
       
   786     info.index          = 0;
       
   787     info.length         = elementCount;
       
   788     info.next           = next;
       
   789     entry = table_create_entry(gdata->reference_table, (void*)elements,
       
   790                          elementCount * get_prim_size(primType), (void*)&info);
       
   791     return entry;
       
   792 }
       
   793 
       
   794 void
       
   795 reference_cleanup(void)
       
   796 {
       
   797     if ( gdata->reference_table == NULL ) {
       
   798         return;
       
   799     }
       
   800     table_cleanup(gdata->reference_table, NULL, NULL);
       
   801     gdata->reference_table = NULL;
       
   802 }
       
   803 
       
   804 void
       
   805 reference_dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list)
       
   806 {
       
   807     dump_instance(env, object_index, list);
       
   808 }
       
   809 
       
   810 void
       
   811 reference_dump_class(JNIEnv *env, ObjectIndex object_index, RefIndex list)
       
   812 {
       
   813     dump_class_and_supers(env, object_index, list);
       
   814 }