Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/jvmti/hprof/hprof_site.c
38829 views
/*1* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/383940/* Allocation site table. */4142/*43* Every object allocation will have a place where it was allocated,44* this is the purpose of the SiteIndex.45*46* The allocation site or SiteIndex is unique via a (class,trace) pair.47*48* The allocation statistics are accumulated in the SiteInfo for each49* site.50*51* This file also contains the heap iterate logic, which is closely52* associated with the site table, the object table, and the53* reference table. Each object has an element in the object table54* and as the heap is traversed, and information contained in each55* object is saved as a linked list of references.56*57*/5859#include "hprof.h"6061typedef struct SiteKey {62ClassIndex cnum; /* Unique class number */63TraceIndex trace_index; /* Trace number */64} SiteKey;6566typedef struct SiteInfo {67int changed; /* Objects at this site changed? */68unsigned n_alloced_instances; /* Total allocated instances */69unsigned n_alloced_bytes; /* Total bytes allocated from here */70unsigned n_live_instances; /* Live instances for this site. */71unsigned n_live_bytes; /* Live byte count for this site. */72} SiteInfo;7374typedef struct IterateInfo {75SiteIndex * site_nums;76int count;77int changed_only;78} IterateInfo;7980/* Private internal functions. */8182static SiteKey*83get_pkey(SiteIndex index)84{85void *key_ptr;86int key_len;8788table_get_key(gdata->site_table, index, &key_ptr, &key_len);89HPROF_ASSERT(key_len==sizeof(SiteKey));90HPROF_ASSERT(key_ptr!=NULL);91return (SiteKey*)key_ptr;92}9394ClassIndex95site_get_class_index(SiteIndex index)96{97SiteKey *pkey;9899pkey = get_pkey(index);100return pkey->cnum;101}102103TraceIndex104site_get_trace_index(SiteIndex index)105{106SiteKey *pkey;107108pkey = get_pkey(index);109return pkey->trace_index;110}111112static SiteInfo *113get_info(SiteIndex index)114{115SiteInfo *info;116117info = (SiteInfo*)table_get_info(gdata->site_table, index);118return info;119}120121static void122list_item(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)123{124SiteKey *pkey;125jlong n_alloced_instances;126jlong n_alloced_bytes;127jlong n_live_instances;128jlong n_live_bytes;129130HPROF_ASSERT(key_ptr!=NULL);131HPROF_ASSERT(key_len==sizeof(SiteKey));132pkey = (SiteKey*)key_ptr;133134if ( info_ptr != NULL ) {135SiteInfo *info;136137info = (SiteInfo *)info_ptr;138n_alloced_instances = info->n_alloced_instances;139n_alloced_bytes = info->n_alloced_bytes;140n_live_instances = info->n_live_instances;141n_live_bytes = info->n_live_bytes;142} else {143n_alloced_instances = 0;144n_alloced_bytes = 0;145n_live_instances = 0;146n_live_bytes = 0;147}148149debug_message( "Site 0x%08x: class=0x%08x, trace=0x%08x, "150"Ninst=(%d,%d), Nbytes=(%d,%d), "151"Nlive=(%d,%d), NliveBytes=(%d,%d)\n",152i,153pkey->cnum,154pkey->trace_index,155jlong_high(n_alloced_instances), jlong_low(n_alloced_instances),156jlong_high(n_alloced_bytes), jlong_low(n_alloced_bytes),157jlong_high(n_live_instances), jlong_low(n_live_instances),158jlong_high(n_live_bytes), jlong_low(n_live_bytes));159}160161static void162collect_iterator(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)163{164IterateInfo *iterate;165166HPROF_ASSERT(key_ptr!=NULL);167HPROF_ASSERT(key_len==sizeof(SiteKey));168HPROF_ASSERT(arg!=NULL);169iterate = (IterateInfo *)arg;170171if ( iterate->changed_only ) {172SiteInfo *info;173174info = (SiteInfo *)info_ptr;175if ( info==NULL || !info->changed ) {176return;177}178}179iterate->site_nums[iterate->count++] = i;180}181182static void183mark_unchanged_iterator(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)184{185SiteInfo *info;186187HPROF_ASSERT(key_ptr!=NULL);188HPROF_ASSERT(key_len==sizeof(SiteKey));189190info = (SiteInfo *)info_ptr;191if ( info != NULL ) {192info->changed = 0;193}194}195196static int197qsort_compare_allocated_bytes(const void *p_site1, const void *p_site2)198{199SiteIndex site1;200SiteIndex site2;201SiteInfo *info1;202SiteInfo *info2;203204HPROF_ASSERT(p_site1!=NULL);205HPROF_ASSERT(p_site2!=NULL);206site1 = *(SiteIndex *)p_site1;207site2 = *(SiteIndex *)p_site2;208info1 = get_info(site1);209info2 = get_info(site2);210return info2->n_alloced_bytes - info1->n_alloced_bytes;211}212213static int214qsort_compare_live_bytes(const void *p_site1, const void *p_site2)215{216SiteIndex site1;217SiteIndex site2;218SiteInfo *info1;219SiteInfo *info2;220221HPROF_ASSERT(p_site1!=NULL);222HPROF_ASSERT(p_site2!=NULL);223site1 = *(SiteIndex *)p_site1;224site2 = *(SiteIndex *)p_site2;225info1 = get_info(site1);226info2 = get_info(site2);227return info2->n_live_bytes - info1->n_live_bytes;228}229230static ClassIndex231find_cnum(jlong class_tag)232{233ClassIndex cnum;234ObjectIndex class_object_index;235SiteIndex class_site_index;236SiteKey *pkey;237238HPROF_ASSERT(class_tag!=(jlong)0);239class_object_index = tag_extract(class_tag);240class_site_index = object_get_site(class_object_index);241pkey = get_pkey(class_site_index);242cnum = pkey->cnum;243return cnum;244}245246/* Create tag and object entry for an untagged object (should be rare) */247static jlong248make_new_tag(jlong class_tag, jlong size, TraceIndex trace_index,249SerialNumber thread_serial_num,250ObjectIndex *pindex, SiteIndex *psite)251{252ObjectIndex object_index;253SiteIndex object_site_index;254255HPROF_ASSERT(class_tag!=(jlong)0);256object_site_index = site_find_or_create(find_cnum(class_tag), trace_index);257object_index = object_new(object_site_index, (jint)size,258OBJECT_SYSTEM, thread_serial_num);259if ( pindex != NULL ) {260*pindex = object_index;261}262if ( psite != NULL ) {263*psite = object_site_index;264}265return tag_create(object_index);266}267268/* Setup tag on root object, if tagged return object index and site index */269static void270setup_tag_on_root(jlong *tag_ptr, jlong class_tag, jlong size,271SerialNumber thread_serial_num,272ObjectIndex *pindex, SiteIndex *psite)273{274HPROF_ASSERT(class_tag!=(jlong)0);275if ( (*tag_ptr) != (jlong)0 ) {276if ( pindex != NULL ) {277*pindex = tag_extract(*tag_ptr);278}279if ( psite != NULL ) {280*psite = object_get_site(tag_extract(*tag_ptr));281}282} else {283/* Create and set the tag. */284*tag_ptr = make_new_tag(class_tag, size, gdata->system_trace_index,285thread_serial_num, pindex, psite);286}287}288289/* External interfaces */290291SiteIndex292site_find_or_create(ClassIndex cnum, TraceIndex trace_index)293{294SiteIndex index;295static SiteKey empty_key;296SiteKey key;297298key = empty_key;299HPROF_ASSERT(cnum!=0);300HPROF_ASSERT(trace_index!=0);301key.cnum = cnum;302key.trace_index = trace_index;303index = table_find_or_create_entry(gdata->site_table,304&key, (int)sizeof(key), NULL, NULL);305return index;306}307308void309site_init(void)310{311HPROF_ASSERT(gdata->site_table==NULL);312gdata->site_table = table_initialize("Site",3131024, 1024, 511, (int)sizeof(SiteInfo));314}315316void317site_list(void)318{319debug_message(320"--------------------- Site Table ------------------------\n");321table_walk_items(gdata->site_table, &list_item, NULL);322debug_message(323"----------------------------------------------------------\n");324}325326void327site_cleanup(void)328{329table_cleanup(gdata->site_table, NULL, NULL);330gdata->site_table = NULL;331}332333void334site_update_stats(SiteIndex index, jint size, jint hits)335{336SiteInfo *info;337338table_lock_enter(gdata->site_table); {339info = get_info(index);340341info->n_live_instances += hits;342info->n_live_bytes += size;343info->changed = 1;344345gdata->total_live_bytes += size;346gdata->total_live_instances += hits;347348if ( size > 0 ) {349info->n_alloced_instances += hits;350info->n_alloced_bytes += size;351gdata->total_alloced_bytes =352jlong_add(gdata->total_alloced_bytes, jint_to_jlong(size));353gdata->total_alloced_instances =354jlong_add(gdata->total_alloced_instances, jint_to_jlong(hits));355}356} table_lock_exit(gdata->site_table);357}358359/* Output allocation sites, up to the given cut-off point, and according360* to the given flags:361*362* SITE_DUMP_INCREMENTAL only dump what's changed since last dump.363* SITE_SORT_BY_ALLOC sort sites by total allocation rather364* than live data.365* SITE_FORCE_GC force a GC before the site dump.366*/367368void369site_write(JNIEnv *env, int flags, double cutoff)370{371HPROF_ASSERT(gdata->site_table!=NULL);372LOG3("site_write", "flags", flags);373374if (flags & SITE_FORCE_GC) {375runGC();376}377378HPROF_ASSERT(gdata->total_live_bytes!=0);379380rawMonitorEnter(gdata->data_access_lock); {381382IterateInfo iterate;383int site_table_size;384double accum_percent;385void * comment_str;386int i;387int cutoff_count;388int nbytes;389390accum_percent = 0;391site_table_size = table_element_count(gdata->site_table);392393(void)memset(&iterate, 0, sizeof(iterate));394nbytes = site_table_size * (int)sizeof(SiteIndex);395if ( nbytes > 0 ) {396iterate.site_nums = HPROF_MALLOC(nbytes);397(void)memset(iterate.site_nums, 0, nbytes);398}399iterate.count = 0;400iterate.changed_only = flags & SITE_DUMP_INCREMENTAL;401table_walk_items(gdata->site_table, &collect_iterator, &iterate);402403site_table_size = iterate.count;404405if (flags & SITE_SORT_BY_ALLOC) {406comment_str = "allocated bytes";407qsort(iterate.site_nums, site_table_size, sizeof(SiteIndex),408&qsort_compare_allocated_bytes);409} else {410comment_str = "live bytes";411qsort(iterate.site_nums, site_table_size, sizeof(SiteIndex),412&qsort_compare_live_bytes);413}414415trace_output_unmarked(env);416417cutoff_count = 0;418for (i = 0; i < site_table_size; i++) {419SiteInfo *info;420SiteIndex index;421double ratio;422423index= iterate.site_nums[i];424HPROF_ASSERT(index!=0);425info = get_info(index);426ratio = (double)info->n_live_bytes / (double)gdata->total_live_bytes;427if (ratio < cutoff) {428break;429}430cutoff_count++;431}432433io_write_sites_header( comment_str,434flags,435cutoff,436gdata->total_live_bytes,437gdata->total_live_instances,438gdata->total_alloced_bytes,439gdata->total_alloced_instances,440cutoff_count);441442for (i = 0; i < cutoff_count; i++) {443SiteInfo *info;444SiteKey *pkey;445SiteIndex index;446char *class_signature;447double ratio;448449index = iterate.site_nums[i];450pkey = get_pkey(index);451info = get_info(index);452453ratio = (double)info->n_live_bytes / (double)gdata->total_live_bytes;454accum_percent += ratio;455456class_signature = string_get(class_get_signature(pkey->cnum));457458io_write_sites_elem(i + 1,459ratio,460accum_percent,461class_signature,462class_get_serial_number(pkey->cnum),463trace_get_serial_number(pkey->trace_index),464info->n_live_bytes,465info->n_live_instances,466info->n_alloced_bytes,467info->n_alloced_instances);468}469470io_write_sites_footer();471472table_walk_items(gdata->site_table, &mark_unchanged_iterator, NULL);473474if ( iterate.site_nums != NULL ) {475HPROF_FREE(iterate.site_nums);476}477478} rawMonitorExit(gdata->data_access_lock);479}480481/* Primitive array data callback for FollowReferences */482static jint JNICALL483cbPrimArrayData(jlong class_tag, jlong size, jlong* tag_ptr,484jint element_count, jvmtiPrimitiveType element_type,485const void* elements, void* user_data)486{487ObjectIndex object_index;488RefIndex ref_index;489RefIndex prev_ref_index;490491HPROF_ASSERT(tag_ptr!=NULL);492HPROF_ASSERT(class_tag!=(jlong)0);493HPROF_ASSERT((*tag_ptr)!=(jlong)0);494if ( class_tag == (jlong)0 || (*tag_ptr) == (jlong)0 ) {495/* We can't do anything with a class_tag==0, just skip it */496return JVMTI_VISIT_OBJECTS;497}498499/* Assume object has been tagged, get object index */500object_index = tag_extract((*tag_ptr));501502/* Save string data */503prev_ref_index = object_get_references(object_index);504ref_index = reference_prim_array(prev_ref_index,505element_type, elements, element_count);506object_set_references(object_index, ref_index);507508return JVMTI_VISIT_OBJECTS;509}510511/* Primitive field data callback for FollowReferences */512static jint JNICALL513cbPrimFieldData(jvmtiHeapReferenceKind reference_kind,514const jvmtiHeapReferenceInfo* reference_info, jlong class_tag,515jlong* tag_ptr, jvalue value, jvmtiPrimitiveType value_type,516void* user_data)517{518ObjectIndex object_index;519jint field_index;520RefIndex ref_index;521RefIndex prev_ref_index;522523HPROF_ASSERT(tag_ptr!=NULL);524HPROF_ASSERT(class_tag!=(jlong)0);525HPROF_ASSERT((*tag_ptr)!=(jlong)0);526if ( class_tag == (jlong)0 || (*tag_ptr) == (jlong)0 ) {527/* We can't do anything with a class_tag==0, just skip it */528return JVMTI_VISIT_OBJECTS;529}530531/* If the field is 0, just skip it, we assume 0 */532if ( value.j == (jlong)0 ) {533return JVMTI_VISIT_OBJECTS;534}535536/* Get field index */537field_index = reference_info->field.index;538539/* We assume the object was tagged */540object_index = tag_extract((*tag_ptr));541542/* Save primitive field data */543prev_ref_index = object_get_references(object_index);544ref_index = reference_prim_field(prev_ref_index, reference_kind,545value_type, value, field_index);546object_set_references(object_index, ref_index);547548return JVMTI_VISIT_OBJECTS;549}550551static SerialNumber552checkThreadSerialNumber(SerialNumber thread_serial_num)553{554TlsIndex tls_index;555556if ( thread_serial_num == gdata->unknown_thread_serial_num ) {557return thread_serial_num;558}559tls_index = tls_find(thread_serial_num);560if ( tls_index != 0 && tls_get_in_heap_dump(tls_index) != 0 ) {561return thread_serial_num;562}563return gdata->unknown_thread_serial_num;564}565566/* Get the object index and thread serial number for this local object */567static void568localReference(jlong *tag_ptr, jlong class_tag, jlong thread_tag,569jlong size, ObjectIndex *pobject_index, SerialNumber *pthread_serial_num)570{571ObjectIndex object_index;572SerialNumber thread_serial_num;573574HPROF_ASSERT(pobject_index!=NULL);575HPROF_ASSERT(pthread_serial_num!=NULL);576HPROF_ASSERT(tag_ptr!=NULL);577HPROF_ASSERT(class_tag!=(jlong)0);578579if ( (*tag_ptr) != (jlong)0 ) {580object_index = tag_extract(*tag_ptr);581thread_serial_num = object_get_thread_serial_number(object_index);582thread_serial_num = checkThreadSerialNumber(thread_serial_num);583} else {584if ( thread_tag != (jlong)0 ) {585ObjectIndex thread_object_index;586587thread_object_index = tag_extract(thread_tag);588thread_serial_num =589object_get_thread_serial_number(thread_object_index);590thread_serial_num = checkThreadSerialNumber(thread_serial_num);591} else {592thread_serial_num = gdata->unknown_thread_serial_num;593}594/* Create and set the tag. */595*tag_ptr = make_new_tag(class_tag, size, gdata->system_trace_index,596thread_serial_num, &object_index, NULL);597}598599HPROF_ASSERT(thread_serial_num!=0);600HPROF_ASSERT(object_index!=0);601*pobject_index = object_index;602*pthread_serial_num = thread_serial_num;603}604605/* Store away plain object reference information */606static jint607objectReference(jvmtiHeapReferenceKind reference_kind,608const jvmtiHeapReferenceInfo* reference_info,609jlong class_tag, jlong size, jlong* tag_ptr,610jlong* referrer_tag_ptr, jint length)611{612ObjectIndex object_index;613jint reference_index;614RefIndex ref_index;615RefIndex prev_ref_index;616ObjectIndex referrer_object_index;617jlong object_tag;618619HPROF_ASSERT(tag_ptr!=NULL);620HPROF_ASSERT(class_tag!=(jlong)0);621HPROF_ASSERT(referrer_tag_ptr!=NULL);622HPROF_ASSERT((*referrer_tag_ptr)!=(jlong)0);623if ( class_tag == (jlong)0 || (*referrer_tag_ptr) == (jlong)0 ) {624/* We can't do anything with a class_tag==0, just skip it */625return JVMTI_VISIT_OBJECTS;626}627628switch ( reference_kind ) {629case JVMTI_HEAP_REFERENCE_CLASS_LOADER:630case JVMTI_HEAP_REFERENCE_INTERFACE:631default:632/* Currently we don't need these */633return JVMTI_VISIT_OBJECTS;634case JVMTI_HEAP_REFERENCE_FIELD:635case JVMTI_HEAP_REFERENCE_STATIC_FIELD:636reference_index = reference_info->field.index;637break;638case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:639reference_index = reference_info->array.index;640break;641case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:642reference_index = reference_info->constant_pool.index;643break;644case JVMTI_HEAP_REFERENCE_SIGNERS:645case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:646reference_index = 0;647break;648}649650/* We assume the referrer is tagged */651referrer_object_index = tag_extract((*referrer_tag_ptr));652653/* Now check the referree */654object_tag = *tag_ptr;655if ( object_tag != (jlong)0 ) {656object_index = tag_extract(object_tag);657} else {658/* Create and set the tag. */659object_tag = make_new_tag(class_tag, size, gdata->system_trace_index,660gdata->unknown_thread_serial_num,661&object_index, NULL);662*tag_ptr = object_tag;663}664HPROF_ASSERT(object_index!=0);665666/* Save reference information */667prev_ref_index = object_get_references(referrer_object_index);668ref_index = reference_obj(prev_ref_index, reference_kind,669object_index, reference_index, length);670object_set_references(referrer_object_index, ref_index);671672return JVMTI_VISIT_OBJECTS;673}674675/* FollowReferences heap_reference_callback */676static jint JNICALL677cbReference(jvmtiHeapReferenceKind reference_kind,678const jvmtiHeapReferenceInfo* reference_info,679jlong class_tag, jlong referrer_class_tag,680jlong size, jlong* tag_ptr,681jlong* referrer_tag_ptr, jint length, void* user_data)682{683ObjectIndex object_index;684685/* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit686* are allowed here (see the JVMTI Spec).687*/688689HPROF_ASSERT(tag_ptr!=NULL);690HPROF_ASSERT(class_tag!=(jlong)0);691if ( class_tag == (jlong)0 ) {692/* We can't do anything with a class_tag==0, just skip it */693return JVMTI_VISIT_OBJECTS;694}695696switch ( reference_kind ) {697698case JVMTI_HEAP_REFERENCE_FIELD:699case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:700case JVMTI_HEAP_REFERENCE_CLASS_LOADER:701case JVMTI_HEAP_REFERENCE_SIGNERS:702case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:703case JVMTI_HEAP_REFERENCE_INTERFACE:704case JVMTI_HEAP_REFERENCE_STATIC_FIELD:705case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:706return objectReference(reference_kind, reference_info,707class_tag, size, tag_ptr, referrer_tag_ptr, length);708709case JVMTI_HEAP_REFERENCE_JNI_GLOBAL: {710SerialNumber trace_serial_num;711SerialNumber gref_serial_num;712TraceIndex trace_index;713SiteIndex object_site_index;714715setup_tag_on_root(tag_ptr, class_tag, size,716gdata->unknown_thread_serial_num,717&object_index, &object_site_index);718if ( object_site_index != 0 ) {719SiteKey *pkey;720721pkey = get_pkey(object_site_index);722trace_index = pkey->trace_index;723} else {724trace_index = gdata->system_trace_index;725}726trace_serial_num = trace_get_serial_number(trace_index);727gref_serial_num = gdata->gref_serial_number_counter++;728io_heap_root_jni_global(object_index, gref_serial_num,729trace_serial_num);730}731break;732733case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: {734char *sig;735SerialNumber class_serial_num;736SiteIndex object_site_index;737738setup_tag_on_root(tag_ptr, class_tag, size,739gdata->unknown_thread_serial_num,740&object_index, &object_site_index);741sig = "Unknown";742class_serial_num = 0;743if ( object_site_index != 0 ) {744SiteKey *pkey;745746pkey = get_pkey(object_site_index);747sig = string_get(class_get_signature(pkey->cnum));748class_serial_num = class_get_serial_number(pkey->cnum);749}750io_heap_root_system_class(object_index, sig, class_serial_num);751}752break;753754case JVMTI_HEAP_REFERENCE_MONITOR:755setup_tag_on_root(tag_ptr, class_tag, size,756gdata->unknown_thread_serial_num,757&object_index, NULL);758io_heap_root_monitor(object_index);759break;760761case JVMTI_HEAP_REFERENCE_STACK_LOCAL: {762SerialNumber thread_serial_num;763jlong thread_tag;764765thread_tag = reference_info->stack_local.thread_tag;766localReference(tag_ptr, class_tag, thread_tag, size,767&object_index, &thread_serial_num);768io_heap_root_java_frame(object_index, thread_serial_num,769reference_info->stack_local.depth);770}771break;772773case JVMTI_HEAP_REFERENCE_JNI_LOCAL: {774SerialNumber thread_serial_num;775jlong thread_tag;776777thread_tag = reference_info->jni_local.thread_tag;778localReference(tag_ptr, class_tag, thread_tag, size,779&object_index, &thread_serial_num);780io_heap_root_jni_local(object_index, thread_serial_num,781reference_info->jni_local.depth);782}783break;784785case JVMTI_HEAP_REFERENCE_THREAD: {786SerialNumber thread_serial_num;787SerialNumber trace_serial_num;788TraceIndex trace_index;789SiteIndex object_site_index;790TlsIndex tls_index;791792/* It is assumed that tag_ptr is referring to a793* java.lang.Thread object here.794*/795if ( (*tag_ptr) != (jlong)0 ) {796setup_tag_on_root(tag_ptr, class_tag, size, 0,797&object_index, &object_site_index);798trace_index = site_get_trace_index(object_site_index);799/* Hopefully the ThreadStart event put this thread's800* correct serial number on it's object.801*/802thread_serial_num = object_get_thread_serial_number(object_index);803} else {804/* Rare situation that a Thread object is not tagged.805* Create special unique thread serial number in this806* case, probably means we never saw a thread start807* or thread end, or even an allocation of the thread808* object.809*/810thread_serial_num = gdata->thread_serial_number_counter++;811setup_tag_on_root(tag_ptr, class_tag, size,812thread_serial_num,813&object_index, &object_site_index);814trace_index = gdata->system_trace_index;815}816/* Get tls_index and set in_heap_dump, if we find it. */817tls_index = tls_find(thread_serial_num);818if ( tls_index != 0 ) {819tls_set_in_heap_dump(tls_index, 1);820}821trace_serial_num = trace_get_serial_number(trace_index);822/* Issue thread object (must be before thread root) */823io_heap_root_thread_object(object_index,824thread_serial_num, trace_serial_num);825/* Issue thread root */826io_heap_root_thread(object_index, thread_serial_num);827}828break;829830case JVMTI_HEAP_REFERENCE_OTHER:831setup_tag_on_root(tag_ptr, class_tag, size,832gdata->unknown_thread_serial_num,833&object_index, NULL);834io_heap_root_unknown(object_index);835break;836837default:838/* Ignore anything else */839break;840841}842843return JVMTI_VISIT_OBJECTS;844}845846void847site_heapdump(JNIEnv *env)848{849850rawMonitorEnter(gdata->data_access_lock); {851852jvmtiHeapCallbacks heapCallbacks;853854/* Remove class dumped status, all classes must be dumped */855class_all_status_remove(CLASS_DUMPED);856857/* Clear in_heap_dump flag */858tls_clear_in_heap_dump();859860/* Dump the last thread traces and get the lists back we need */861tls_dump_traces(env);862863/* Write header for heap dump */864io_heap_header(gdata->total_live_instances, gdata->total_live_bytes);865866/* Setup a clean reference table */867reference_init();868869/* Walk over all reachable objects and dump out roots */870gdata->gref_serial_number_counter = gdata->gref_serial_number_start;871872/* Issue thread object for fake non-existent unknown thread873* just in case someone refers to it. Real threads are handled874* during iterate over reachable objects.875*/876io_heap_root_thread_object(0, gdata->unknown_thread_serial_num,877trace_get_serial_number(gdata->system_trace_index));878879/* Iterate over heap and get the real stuff */880(void)memset(&heapCallbacks, 0, sizeof(heapCallbacks));881882/* Select callbacks */883heapCallbacks.heap_reference_callback = &cbReference;884if ( gdata->primfields == JNI_TRUE ) {885heapCallbacks.primitive_field_callback = &cbPrimFieldData;886}887if ( gdata->primarrays == JNI_TRUE ) {888heapCallbacks.array_primitive_value_callback = &cbPrimArrayData;889}890followReferences(&heapCallbacks, (void*)NULL);891892/* Process reference information. */893object_reference_dump(env);894object_clear_references();895reference_cleanup();896897/* Dump the last thread traces and get the lists back we need */898tls_dump_traces(env);899900/* Write out footer for heap dump */901io_heap_footer();902903} rawMonitorExit(gdata->data_access_lock);904}905906907