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 }