jdk/src/jdk.hprof.agent/share/native/libhprof/hprof_site.c
changeset 32253 637b00638ed6
parent 32252 78117959e115
parent 32249 ba2c9c7773b6
child 32255 cc8c8786ef91
equal deleted inserted replaced
32252:78117959e115 32253:637b00638ed6
     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 }