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 /* Allocation site table. */
  42 
  43 /*
  44  * Every object allocation will have a place where it was allocated,
  45  *  this is the purpose of the SiteIndex.
  46  *
  47  * The allocation site or SiteIndex is unique via a (class,trace) pair.
  48  *
  49  * The allocation statistics are accumulated in the SiteInfo for each
  50  *   site.
  51  *
  52  * This file also contains the heap iterate logic, which is closely
  53  *   associated with the site table, the object table, and the
  54  *   reference table. Each object has an element in the object table
  55  *   and as the heap is traversed, and information contained in each
  56  *   object is saved as a linked list of references.
  57  *
  58  */
  59 
  60 #include "hprof.h"
  61 
  62 typedef struct SiteKey {
  63     ClassIndex cnum;         /* Unique class number */
  64     TraceIndex trace_index;  /* Trace number */
  65 } SiteKey;
  66 
  67 typedef struct SiteInfo {
  68     int         changed;               /* Objects at this site changed? */
  69     unsigned    n_alloced_instances;   /* Total allocated instances */
  70     unsigned    n_alloced_bytes;       /* Total bytes allocated from here */
  71     unsigned    n_live_instances;      /* Live instances for this site. */
  72     unsigned    n_live_bytes;          /* Live byte count for this site. */
  73 } SiteInfo;
  74 
  75 typedef struct IterateInfo {
  76     SiteIndex * site_nums;
  77     int         count;
  78     int         changed_only;
  79 } IterateInfo;
  80 
  81 /* Private internal functions. */
  82 
  83 static SiteKey*
  84 get_pkey(SiteIndex index)
  85 {
  86     void *key_ptr;
  87     int   key_len;
  88 
  89     table_get_key(gdata->site_table, index, &key_ptr, &key_len);
  90     HPROF_ASSERT(key_len==sizeof(SiteKey));
  91     HPROF_ASSERT(key_ptr!=NULL);
  92     return (SiteKey*)key_ptr;
  93 }
  94 
  95 ClassIndex
  96 site_get_class_index(SiteIndex index)
  97 {
  98     SiteKey *pkey;
  99 
 100     pkey = get_pkey(index);
 101     return pkey->cnum;
 102 }
 103 
 104 TraceIndex
 105 site_get_trace_index(SiteIndex index)
 106 {
 107     SiteKey *pkey;
 108 
 109     pkey = get_pkey(index);
 110     return pkey->trace_index;
 111 }
 112 
 113 static SiteInfo *
 114 get_info(SiteIndex index)
 115 {
 116     SiteInfo *info;
 117 
 118     info = (SiteInfo*)table_get_info(gdata->site_table, index);
 119     return info;
 120 }
 121 
 122 static void
 123 list_item(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
 124 {
 125     SiteKey         *pkey;
 126     jlong            n_alloced_instances;
 127     jlong            n_alloced_bytes;
 128     jlong            n_live_instances;
 129     jlong            n_live_bytes;
 130 
 131     HPROF_ASSERT(key_ptr!=NULL);
 132     HPROF_ASSERT(key_len==sizeof(SiteKey));
 133     pkey = (SiteKey*)key_ptr;
 134 
 135     if ( info_ptr != NULL ) {
 136         SiteInfo *info;
 137 
 138         info = (SiteInfo *)info_ptr;
 139         n_alloced_instances    = info->n_alloced_instances;
 140         n_alloced_bytes        = info->n_alloced_bytes;
 141         n_live_instances       = info->n_live_instances;
 142         n_live_bytes           = info->n_live_bytes;
 143     } else {
 144         n_alloced_instances    = 0;
 145         n_alloced_bytes        = 0;
 146         n_live_instances       = 0;
 147         n_live_bytes           = 0;
 148     }
 149 
 150     debug_message( "Site 0x%08x: class=0x%08x, trace=0x%08x, "
 151                           "Ninst=(%d,%d), Nbytes=(%d,%d), "
 152                           "Nlive=(%d,%d), NliveBytes=(%d,%d)\n",
 153              i,
 154              pkey->cnum,
 155              pkey->trace_index,
 156              jlong_high(n_alloced_instances), jlong_low(n_alloced_instances),
 157              jlong_high(n_alloced_bytes),     jlong_low(n_alloced_bytes),
 158              jlong_high(n_live_instances),    jlong_low(n_live_instances),
 159              jlong_high(n_live_bytes),        jlong_low(n_live_bytes));
 160 }
 161 
 162 static void
 163 collect_iterator(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
 164 {
 165     IterateInfo     *iterate;
 166 
 167     HPROF_ASSERT(key_ptr!=NULL);
 168     HPROF_ASSERT(key_len==sizeof(SiteKey));
 169     HPROF_ASSERT(arg!=NULL);
 170     iterate = (IterateInfo *)arg;
 171 
 172     if ( iterate->changed_only ) {
 173         SiteInfo *info;
 174 
 175         info = (SiteInfo *)info_ptr;
 176         if ( info==NULL || !info->changed ) {
 177             return;
 178         }
 179     }
 180     iterate->site_nums[iterate->count++] = i;
 181 }
 182 
 183 static void
 184 mark_unchanged_iterator(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
 185 {
 186     SiteInfo *info;
 187 
 188     HPROF_ASSERT(key_ptr!=NULL);
 189     HPROF_ASSERT(key_len==sizeof(SiteKey));
 190 
 191     info = (SiteInfo *)info_ptr;
 192     if ( info != NULL ) {
 193         info->changed = 0;
 194     }
 195 }
 196 
 197 static int
 198 qsort_compare_allocated_bytes(const void *p_site1, const void *p_site2)
 199 {
 200     SiteIndex  site1;
 201     SiteIndex  site2;
 202     SiteInfo  *info1;
 203     SiteInfo  *info2;
 204 
 205     HPROF_ASSERT(p_site1!=NULL);
 206     HPROF_ASSERT(p_site2!=NULL);
 207     site1 = *(SiteIndex *)p_site1;
 208     site2 = *(SiteIndex *)p_site2;
 209     info1 = get_info(site1);
 210     info2 = get_info(site2);
 211     return info2->n_alloced_bytes - info1->n_alloced_bytes;
 212 }
 213 
 214 static int
 215 qsort_compare_live_bytes(const void *p_site1, const void *p_site2)
 216 {
 217     SiteIndex  site1;
 218     SiteIndex  site2;
 219     SiteInfo  *info1;
 220     SiteInfo  *info2;
 221 
 222     HPROF_ASSERT(p_site1!=NULL);
 223     HPROF_ASSERT(p_site2!=NULL);
 224     site1 = *(SiteIndex *)p_site1;
 225     site2 = *(SiteIndex *)p_site2;
 226     info1 = get_info(site1);
 227     info2 = get_info(site2);
 228     return info2->n_live_bytes - info1->n_live_bytes;
 229 }
 230 
 231 static ClassIndex
 232 find_cnum(jlong class_tag)
 233 {
 234     ClassIndex  cnum;
 235     ObjectIndex class_object_index;
 236     SiteIndex   class_site_index;
 237     SiteKey    *pkey;
 238 
 239     HPROF_ASSERT(class_tag!=(jlong)0);
 240     class_object_index = tag_extract(class_tag);
 241     class_site_index = object_get_site(class_object_index);
 242     pkey = get_pkey(class_site_index);
 243     cnum = pkey->cnum;
 244     return cnum;
 245 }
 246 
 247 /* Create tag and object entry for an untagged object (should be rare) */
 248 static jlong
 249 make_new_tag(jlong class_tag, jlong size, TraceIndex trace_index,
 250                   SerialNumber thread_serial_num,
 251                   ObjectIndex *pindex, SiteIndex *psite)
 252 {
 253     ObjectIndex object_index;
 254     SiteIndex   object_site_index;
 255 
 256     HPROF_ASSERT(class_tag!=(jlong)0);
 257     object_site_index = site_find_or_create(find_cnum(class_tag), trace_index);
 258     object_index      = object_new(object_site_index, (jint)size,
 259                                    OBJECT_SYSTEM, thread_serial_num);
 260     if ( pindex != NULL ) {
 261         *pindex = object_index;
 262     }
 263     if ( psite != NULL ) {
 264         *psite = object_site_index;
 265     }
 266     return tag_create(object_index);
 267 }
 268 
 269 /* Setup tag on root object, if tagged return object index and site index */
 270 static void
 271 setup_tag_on_root(jlong *tag_ptr, jlong class_tag, jlong size,
 272                   SerialNumber thread_serial_num,
 273                   ObjectIndex *pindex, SiteIndex *psite)
 274 {
 275     HPROF_ASSERT(class_tag!=(jlong)0);
 276     if ( (*tag_ptr) != (jlong)0 ) {
 277         if ( pindex != NULL ) {
 278             *pindex = tag_extract(*tag_ptr);
 279         }
 280         if ( psite != NULL ) {
 281             *psite = object_get_site(tag_extract(*tag_ptr));
 282         }
 283     } else {
 284         /* Create and set the tag. */
 285         *tag_ptr = make_new_tag(class_tag, size, gdata->system_trace_index,
 286                   thread_serial_num, pindex, psite);
 287     }
 288 }
 289 
 290 /* External interfaces */
 291 
 292 SiteIndex
 293 site_find_or_create(ClassIndex cnum, TraceIndex trace_index)
 294 {
 295     SiteIndex index;
 296     static SiteKey  empty_key;
 297     SiteKey   key;
 298 
 299     key = empty_key;
 300     HPROF_ASSERT(cnum!=0);
 301     HPROF_ASSERT(trace_index!=0);
 302     key.cnum        = cnum;
 303     key.trace_index = trace_index;
 304     index = table_find_or_create_entry(gdata->site_table,
 305                             &key, (int)sizeof(key), NULL, NULL);
 306     return index;
 307 }
 308 
 309 void
 310 site_init(void)
 311 {
 312     HPROF_ASSERT(gdata->site_table==NULL);
 313     gdata->site_table = table_initialize("Site",
 314                             1024, 1024, 511, (int)sizeof(SiteInfo));
 315 }
 316 
 317 void
 318 site_list(void)
 319 {
 320     debug_message(
 321         "--------------------- Site Table ------------------------\n");
 322     table_walk_items(gdata->site_table, &list_item, NULL);
 323     debug_message(
 324         "----------------------------------------------------------\n");
 325 }
 326 
 327 void
 328 site_cleanup(void)
 329 {
 330     table_cleanup(gdata->site_table, NULL, NULL);
 331     gdata->site_table = NULL;
 332 }
 333 
 334 void
 335 site_update_stats(SiteIndex index, jint size, jint hits)
 336 {
 337     SiteInfo *info;
 338 
 339     table_lock_enter(gdata->site_table); {
 340         info = get_info(index);
 341 
 342         info->n_live_instances          += hits;
 343         info->n_live_bytes              += size;
 344         info->changed                   = 1;
 345 
 346         gdata->total_live_bytes         += size;
 347         gdata->total_live_instances     += hits;
 348 
 349         if ( size > 0 ) {
 350             info->n_alloced_instances   += hits;
 351             info->n_alloced_bytes       += size;
 352             gdata->total_alloced_bytes =
 353                 jlong_add(gdata->total_alloced_bytes, jint_to_jlong(size));
 354             gdata->total_alloced_instances =
 355                 jlong_add(gdata->total_alloced_instances, jint_to_jlong(hits));
 356         }
 357     } table_lock_exit(gdata->site_table);
 358 }
 359 
 360 /* Output allocation sites, up to the given cut-off point, and according
 361  * to the given flags:
 362  *
 363  *      SITE_DUMP_INCREMENTAL only dump what's changed since last dump.
 364  *      SITE_SORT_BY_ALLOC    sort sites by total allocation rather
 365  *                                  than live data.
 366  *      SITE_FORCE_GC         force a GC before the site dump.
 367  */
 368 
 369 void
 370 site_write(JNIEnv *env, int flags, double cutoff)
 371 {
 372     HPROF_ASSERT(gdata->site_table!=NULL);
 373     LOG3("site_write", "flags", flags);
 374 
 375     if (flags & SITE_FORCE_GC) {
 376         runGC();
 377     }
 378 
 379     HPROF_ASSERT(gdata->total_live_bytes!=0);
 380 
 381     rawMonitorEnter(gdata->data_access_lock); {
 382 
 383         IterateInfo     iterate;
 384         int             site_table_size;
 385         double          accum_percent;
 386         void *          comment_str;
 387         int             i;
 388         int             cutoff_count;
 389         int             nbytes;
 390 
 391         accum_percent = 0;
 392         site_table_size = table_element_count(gdata->site_table);
 393 
 394         (void)memset(&iterate, 0, sizeof(iterate));
 395         nbytes            = site_table_size * (int)sizeof(SiteIndex);
 396         if ( nbytes > 0 ) {
 397             iterate.site_nums = HPROF_MALLOC(nbytes);
 398             (void)memset(iterate.site_nums, 0, nbytes);
 399         }
 400         iterate.count   = 0;
 401         iterate.changed_only = flags & SITE_DUMP_INCREMENTAL;
 402         table_walk_items(gdata->site_table, &collect_iterator, &iterate);
 403 
 404         site_table_size = iterate.count;
 405 
 406         if (flags & SITE_SORT_BY_ALLOC) {
 407             comment_str = "allocated bytes";
 408             qsort(iterate.site_nums, site_table_size, sizeof(SiteIndex),
 409                     &qsort_compare_allocated_bytes);
 410         } else {
 411             comment_str = "live bytes";
 412             qsort(iterate.site_nums, site_table_size, sizeof(SiteIndex),
 413                     &qsort_compare_live_bytes);
 414         }
 415 
 416         trace_output_unmarked(env);
 417 
 418         cutoff_count = 0;
 419         for (i = 0; i < site_table_size; i++) {
 420             SiteInfo   *info;
 421             SiteIndex   index;
 422             double      ratio;
 423 
 424             index= iterate.site_nums[i];
 425             HPROF_ASSERT(index!=0);
 426             info        = get_info(index);
 427             ratio       = (double)info->n_live_bytes / (double)gdata->total_live_bytes;
 428             if (ratio < cutoff) {
 429                 break;
 430             }
 431             cutoff_count++;
 432         }
 433 
 434         io_write_sites_header(  comment_str,
 435                                 flags,
 436                                 cutoff,
 437                                 gdata->total_live_bytes,
 438                                 gdata->total_live_instances,
 439                                 gdata->total_alloced_bytes,
 440                                 gdata->total_alloced_instances,
 441                                 cutoff_count);
 442 
 443         for (i = 0; i < cutoff_count; i++) {
 444             SiteInfo     *info;
 445             SiteKey      *pkey;
 446             SiteIndex     index;
 447             char         *class_signature;
 448             double        ratio;
 449 
 450             index = iterate.site_nums[i];
 451             pkey         = get_pkey(index);
 452             info         = get_info(index);
 453 
 454             ratio       = (double)info->n_live_bytes / (double)gdata->total_live_bytes;
 455             accum_percent += ratio;
 456 
 457             class_signature  = string_get(class_get_signature(pkey->cnum));
 458 
 459             io_write_sites_elem(i + 1,
 460                                 ratio,
 461                                 accum_percent,
 462                                 class_signature,
 463                                 class_get_serial_number(pkey->cnum),
 464                                 trace_get_serial_number(pkey->trace_index),
 465                                 info->n_live_bytes,
 466                                 info->n_live_instances,
 467                                 info->n_alloced_bytes,
 468                                 info->n_alloced_instances);
 469         }
 470 
 471         io_write_sites_footer();
 472 
 473         table_walk_items(gdata->site_table, &mark_unchanged_iterator, NULL);
 474 
 475         if ( iterate.site_nums != NULL ) {
 476             HPROF_FREE(iterate.site_nums);
 477         }
 478 
 479     } rawMonitorExit(gdata->data_access_lock);
 480 }
 481 
 482 /* Primitive array data callback for FollowReferences */
 483 static jint JNICALL
 484 cbPrimArrayData(jlong class_tag, jlong size, jlong* tag_ptr,
 485          jint element_count, jvmtiPrimitiveType element_type,
 486          const void* elements, void* user_data)
 487 {
 488     ObjectIndex   object_index;
 489     RefIndex      ref_index;
 490     RefIndex      prev_ref_index;
 491 
 492     HPROF_ASSERT(tag_ptr!=NULL);
 493     HPROF_ASSERT(class_tag!=(jlong)0);
 494     HPROF_ASSERT((*tag_ptr)!=(jlong)0);
 495     if ( class_tag == (jlong)0 || (*tag_ptr) == (jlong)0 ) {
 496         /* We can't do anything with a class_tag==0, just skip it */
 497         return JVMTI_VISIT_OBJECTS;
 498     }
 499 
 500     /* Assume object has been tagged, get object index */
 501     object_index = tag_extract((*tag_ptr));
 502 
 503     /* Save string data */
 504     prev_ref_index = object_get_references(object_index);
 505     ref_index = reference_prim_array(prev_ref_index,
 506                   element_type, elements, element_count);
 507     object_set_references(object_index, ref_index);
 508 
 509     return JVMTI_VISIT_OBJECTS;
 510 }
 511 
 512 /* Primitive field data callback for FollowReferences */
 513 static jint JNICALL
 514 cbPrimFieldData(jvmtiHeapReferenceKind reference_kind,
 515          const jvmtiHeapReferenceInfo* reference_info, jlong class_tag,
 516          jlong* tag_ptr, jvalue value, jvmtiPrimitiveType value_type,
 517          void* user_data)
 518 {
 519     ObjectIndex   object_index;
 520     jint          field_index;
 521     RefIndex      ref_index;
 522     RefIndex      prev_ref_index;
 523 
 524     HPROF_ASSERT(tag_ptr!=NULL);
 525     HPROF_ASSERT(class_tag!=(jlong)0);
 526     HPROF_ASSERT((*tag_ptr)!=(jlong)0);
 527     if ( class_tag == (jlong)0 || (*tag_ptr) == (jlong)0 ) {
 528         /* We can't do anything with a class_tag==0, just skip it */
 529         return JVMTI_VISIT_OBJECTS;
 530     }
 531 
 532     /* If the field is 0, just skip it, we assume 0 */
 533     if ( value.j == (jlong)0 ) {
 534         return JVMTI_VISIT_OBJECTS;
 535     }
 536 
 537     /* Get field index */
 538     field_index = reference_info->field.index;
 539 
 540     /* We assume the object was tagged */
 541     object_index = tag_extract((*tag_ptr));
 542 
 543     /* Save primitive field data */
 544     prev_ref_index = object_get_references(object_index);
 545     ref_index = reference_prim_field(prev_ref_index, reference_kind,
 546                   value_type, value, field_index);
 547     object_set_references(object_index, ref_index);
 548 
 549     return JVMTI_VISIT_OBJECTS;
 550 }
 551 
 552 static SerialNumber
 553 checkThreadSerialNumber(SerialNumber thread_serial_num)
 554 {
 555     TlsIndex tls_index;
 556 
 557     if ( thread_serial_num == gdata->unknown_thread_serial_num ) {
 558         return thread_serial_num;
 559     }
 560     tls_index = tls_find(thread_serial_num);
 561     if ( tls_index != 0 && tls_get_in_heap_dump(tls_index) != 0 ) {
 562         return thread_serial_num;
 563     }
 564     return gdata->unknown_thread_serial_num;
 565 }
 566 
 567 /* Get the object index and thread serial number for this local object */
 568 static void
 569 localReference(jlong *tag_ptr, jlong class_tag, jlong thread_tag,
 570      jlong size, ObjectIndex *pobject_index, SerialNumber *pthread_serial_num)
 571 {
 572     ObjectIndex  object_index;
 573     SerialNumber thread_serial_num;
 574 
 575     HPROF_ASSERT(pobject_index!=NULL);
 576     HPROF_ASSERT(pthread_serial_num!=NULL);
 577     HPROF_ASSERT(tag_ptr!=NULL);
 578     HPROF_ASSERT(class_tag!=(jlong)0);
 579 
 580     if ( (*tag_ptr) != (jlong)0 ) {
 581         object_index = tag_extract(*tag_ptr);
 582         thread_serial_num = object_get_thread_serial_number(object_index);
 583         thread_serial_num = checkThreadSerialNumber(thread_serial_num);
 584     } else {
 585         if ( thread_tag != (jlong)0 ) {
 586             ObjectIndex thread_object_index;
 587 
 588             thread_object_index = tag_extract(thread_tag);
 589             thread_serial_num =
 590                    object_get_thread_serial_number(thread_object_index);
 591             thread_serial_num = checkThreadSerialNumber(thread_serial_num);
 592         } else {
 593             thread_serial_num = gdata->unknown_thread_serial_num;
 594         }
 595         /* Create and set the tag. */
 596         *tag_ptr = make_new_tag(class_tag, size, gdata->system_trace_index,
 597                   thread_serial_num, &object_index, NULL);
 598     }
 599 
 600     HPROF_ASSERT(thread_serial_num!=0);
 601     HPROF_ASSERT(object_index!=0);
 602     *pobject_index      = object_index;
 603     *pthread_serial_num = thread_serial_num;
 604 }
 605 
 606 /* Store away plain object reference information */
 607 static jint
 608 objectReference(jvmtiHeapReferenceKind reference_kind,
 609                   const jvmtiHeapReferenceInfo* reference_info,
 610                   jlong class_tag, jlong size, jlong* tag_ptr,
 611                   jlong* referrer_tag_ptr, jint length)
 612 {
 613     ObjectIndex   object_index;
 614     jint          reference_index;
 615     RefIndex      ref_index;
 616     RefIndex      prev_ref_index;
 617     ObjectIndex   referrer_object_index;
 618     jlong         object_tag;
 619 
 620     HPROF_ASSERT(tag_ptr!=NULL);
 621     HPROF_ASSERT(class_tag!=(jlong)0);
 622     HPROF_ASSERT(referrer_tag_ptr!=NULL);
 623     HPROF_ASSERT((*referrer_tag_ptr)!=(jlong)0);
 624     if ( class_tag == (jlong)0 || (*referrer_tag_ptr) == (jlong)0 ) {
 625         /* We can't do anything with a class_tag==0, just skip it */
 626         return JVMTI_VISIT_OBJECTS;
 627     }
 628 
 629     switch ( reference_kind ) {
 630         case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
 631         case JVMTI_HEAP_REFERENCE_INTERFACE:
 632         default:
 633             /* Currently we don't need these */
 634             return JVMTI_VISIT_OBJECTS;
 635         case JVMTI_HEAP_REFERENCE_FIELD:
 636         case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
 637             reference_index = reference_info->field.index;
 638             break;
 639         case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
 640             reference_index = reference_info->array.index;
 641             break;
 642         case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
 643             reference_index = reference_info->constant_pool.index;
 644             break;
 645         case JVMTI_HEAP_REFERENCE_SIGNERS:
 646         case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
 647             reference_index = 0;
 648             break;
 649     }
 650 
 651     /* We assume the referrer is tagged */
 652     referrer_object_index = tag_extract((*referrer_tag_ptr));
 653 
 654     /* Now check the referree */
 655     object_tag = *tag_ptr;
 656     if ( object_tag != (jlong)0 ) {
 657         object_index = tag_extract(object_tag);
 658     } else {
 659         /* Create and set the tag. */
 660         object_tag = make_new_tag(class_tag, size, gdata->system_trace_index,
 661                                   gdata->unknown_thread_serial_num,
 662                                   &object_index, NULL);
 663         *tag_ptr   = object_tag;
 664     }
 665     HPROF_ASSERT(object_index!=0);
 666 
 667     /* Save reference information */
 668     prev_ref_index = object_get_references(referrer_object_index);
 669     ref_index = reference_obj(prev_ref_index, reference_kind,
 670                     object_index, reference_index, length);
 671     object_set_references(referrer_object_index, ref_index);
 672 
 673     return JVMTI_VISIT_OBJECTS;
 674 }
 675 
 676 /* FollowReferences heap_reference_callback */
 677 static jint JNICALL
 678 cbReference(jvmtiHeapReferenceKind reference_kind,
 679                   const jvmtiHeapReferenceInfo* reference_info,
 680                   jlong class_tag, jlong referrer_class_tag,
 681                   jlong size, jlong* tag_ptr,
 682                   jlong* referrer_tag_ptr, jint length, void* user_data)
 683 {
 684     ObjectIndex   object_index;
 685 
 686    /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit
 687     *   are allowed here (see the JVMTI Spec).
 688     */
 689 
 690     HPROF_ASSERT(tag_ptr!=NULL);
 691     HPROF_ASSERT(class_tag!=(jlong)0);
 692     if ( class_tag == (jlong)0 ) {
 693         /* We can't do anything with a class_tag==0, just skip it */
 694         return JVMTI_VISIT_OBJECTS;
 695     }
 696 
 697     switch ( reference_kind ) {
 698 
 699         case JVMTI_HEAP_REFERENCE_FIELD:
 700         case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
 701         case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
 702         case JVMTI_HEAP_REFERENCE_SIGNERS:
 703         case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
 704         case JVMTI_HEAP_REFERENCE_INTERFACE:
 705         case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
 706         case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
 707             return objectReference(reference_kind, reference_info,
 708                    class_tag, size, tag_ptr, referrer_tag_ptr, length);
 709 
 710         case JVMTI_HEAP_REFERENCE_JNI_GLOBAL: {
 711                 SerialNumber trace_serial_num;
 712                 SerialNumber gref_serial_num;
 713                 TraceIndex   trace_index;
 714                 SiteIndex    object_site_index;
 715 
 716                 setup_tag_on_root(tag_ptr, class_tag, size,
 717                                   gdata->unknown_thread_serial_num,
 718                                   &object_index, &object_site_index);
 719                 if ( object_site_index != 0 ) {
 720                     SiteKey     *pkey;
 721 
 722                     pkey = get_pkey(object_site_index);
 723                     trace_index = pkey->trace_index;
 724                 } else {
 725                     trace_index = gdata->system_trace_index;
 726                 }
 727                 trace_serial_num = trace_get_serial_number(trace_index);
 728                 gref_serial_num  = gdata->gref_serial_number_counter++;
 729                 io_heap_root_jni_global(object_index, gref_serial_num,
 730                                         trace_serial_num);
 731             }
 732             break;
 733 
 734         case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: {
 735                 char        *sig;
 736                 SerialNumber class_serial_num;
 737                 SiteIndex    object_site_index;
 738 
 739                 setup_tag_on_root(tag_ptr, class_tag, size,
 740                                   gdata->unknown_thread_serial_num,
 741                                   &object_index, &object_site_index);
 742                 sig = "Unknown";
 743                 class_serial_num = 0;
 744                 if ( object_site_index != 0 ) {
 745                     SiteKey *pkey;
 746 
 747                     pkey = get_pkey(object_site_index);
 748                     sig = string_get(class_get_signature(pkey->cnum));
 749                     class_serial_num = class_get_serial_number(pkey->cnum);
 750                 }
 751                 io_heap_root_system_class(object_index, sig, class_serial_num);
 752             }
 753             break;
 754 
 755         case JVMTI_HEAP_REFERENCE_MONITOR:
 756             setup_tag_on_root(tag_ptr, class_tag, size,
 757                               gdata->unknown_thread_serial_num,
 758                               &object_index, NULL);
 759             io_heap_root_monitor(object_index);
 760             break;
 761 
 762         case JVMTI_HEAP_REFERENCE_STACK_LOCAL:  {
 763                 SerialNumber thread_serial_num;
 764                 jlong        thread_tag;
 765 
 766                 thread_tag = reference_info->stack_local.thread_tag;
 767                 localReference(tag_ptr, class_tag, thread_tag, size,
 768                              &object_index, &thread_serial_num);
 769                 io_heap_root_java_frame(object_index, thread_serial_num,
 770                              reference_info->stack_local.depth);
 771             }
 772             break;
 773 
 774         case JVMTI_HEAP_REFERENCE_JNI_LOCAL: {
 775                 SerialNumber thread_serial_num;
 776                 jlong        thread_tag;
 777 
 778                 thread_tag = reference_info->jni_local.thread_tag;
 779                 localReference(tag_ptr, class_tag, thread_tag, size,
 780                              &object_index, &thread_serial_num);
 781                 io_heap_root_jni_local(object_index, thread_serial_num,
 782                              reference_info->jni_local.depth);
 783             }
 784             break;
 785 
 786         case JVMTI_HEAP_REFERENCE_THREAD: {
 787                 SerialNumber thread_serial_num;
 788                 SerialNumber trace_serial_num;
 789                 TraceIndex   trace_index;
 790                 SiteIndex    object_site_index;
 791                 TlsIndex     tls_index;
 792 
 793                 /* It is assumed that tag_ptr is referring to a
 794                  *      java.lang.Thread object here.
 795                  */
 796                 if ( (*tag_ptr) != (jlong)0 ) {
 797                     setup_tag_on_root(tag_ptr, class_tag, size, 0,
 798                                       &object_index, &object_site_index);
 799                     trace_index       = site_get_trace_index(object_site_index);
 800                     /* Hopefully the ThreadStart event put this thread's
 801                      *   correct serial number on it's object.
 802                      */
 803                     thread_serial_num = object_get_thread_serial_number(object_index);
 804                 } else {
 805                     /* Rare situation that a Thread object is not tagged.
 806                      *   Create special unique thread serial number in this
 807                      *   case, probably means we never saw a thread start
 808                      *   or thread end, or even an allocation of the thread
 809                      *   object.
 810                      */
 811                     thread_serial_num = gdata->thread_serial_number_counter++;
 812                     setup_tag_on_root(tag_ptr, class_tag, size,
 813                                       thread_serial_num,
 814                                       &object_index, &object_site_index);
 815                     trace_index = gdata->system_trace_index;
 816                 }
 817                 /* Get tls_index and set in_heap_dump, if we find it. */
 818                 tls_index = tls_find(thread_serial_num);
 819                 if ( tls_index != 0 ) {
 820                     tls_set_in_heap_dump(tls_index, 1);
 821                 }
 822                 trace_serial_num = trace_get_serial_number(trace_index);
 823                 /* Issue thread object (must be before thread root) */
 824                 io_heap_root_thread_object(object_index,
 825                                  thread_serial_num, trace_serial_num);
 826                 /* Issue thread root */
 827                 io_heap_root_thread(object_index, thread_serial_num);
 828             }
 829             break;
 830 
 831         case JVMTI_HEAP_REFERENCE_OTHER:
 832             setup_tag_on_root(tag_ptr, class_tag, size,
 833                               gdata->unknown_thread_serial_num,
 834                               &object_index, NULL);
 835             io_heap_root_unknown(object_index);
 836             break;
 837 
 838        default:
 839             /* Ignore anything else */
 840             break;
 841 
 842     }
 843 
 844     return JVMTI_VISIT_OBJECTS;
 845 }
 846 
 847 void
 848 site_heapdump(JNIEnv *env)
 849 {
 850 
 851     rawMonitorEnter(gdata->data_access_lock); {
 852 
 853         jvmtiHeapCallbacks heapCallbacks;
 854 
 855         /* Remove class dumped status, all classes must be dumped */
 856         class_all_status_remove(CLASS_DUMPED);
 857 
 858         /* Clear in_heap_dump flag */
 859         tls_clear_in_heap_dump();
 860 
 861         /* Dump the last thread traces and get the lists back we need */
 862         tls_dump_traces(env);
 863 
 864         /* Write header for heap dump */
 865         io_heap_header(gdata->total_live_instances, gdata->total_live_bytes);
 866 
 867         /* Setup a clean reference table */
 868         reference_init();
 869 
 870         /* Walk over all reachable objects and dump out roots */
 871         gdata->gref_serial_number_counter = gdata->gref_serial_number_start;
 872 
 873         /* Issue thread object for fake non-existent unknown thread
 874          *   just in case someone refers to it. Real threads are handled
 875          *   during iterate over reachable objects.
 876          */
 877         io_heap_root_thread_object(0, gdata->unknown_thread_serial_num,
 878                         trace_get_serial_number(gdata->system_trace_index));
 879 
 880         /* Iterate over heap and get the real stuff */
 881         (void)memset(&heapCallbacks, 0, sizeof(heapCallbacks));
 882 
 883         /* Select callbacks */
 884         heapCallbacks.heap_reference_callback       = &cbReference;
 885         if ( gdata->primfields == JNI_TRUE ) {
 886             heapCallbacks.primitive_field_callback  = &cbPrimFieldData;
 887         }
 888         if ( gdata->primarrays == JNI_TRUE ) {
 889             heapCallbacks.array_primitive_value_callback  = &cbPrimArrayData;
 890         }
 891         followReferences(&heapCallbacks, (void*)NULL);
 892 
 893         /* Process reference information. */
 894         object_reference_dump(env);
 895         object_clear_references();
 896         reference_cleanup();
 897 
 898         /* Dump the last thread traces and get the lists back we need */
 899         tls_dump_traces(env);
 900 
 901         /* Write out footer for heap dump */
 902         io_heap_footer();
 903 
 904     } rawMonitorExit(gdata->data_access_lock);
 905 }