1 /*
   2  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30  */
  31 
  32 /*
  33  * This source code is provided to illustrate the usage of a given feature
  34  * or technique and has been deliberately simplified. Additional steps
  35  * required for a production-quality application, such as security checks,
  36  * input validation and proper error handling, might not be present in
  37  * this sample code.
  38  */
  39 
  40 
  41 /* Object table. */
  42 
  43 /*
  44  * An Object is unique by it's allocation site (SiteIndex), it's size,
  45  *   it's kind, and it's serial number. Normally only the serial number
  46  *   would have been necessary for heap=dump, and these other items
  47  *   could have been moved to the ObjectInfo. An optimization left
  48  *   to the reader. Lookups are not normally done on ObjectIndex's
  49  *   anyway because we typically know when to create them.
  50  *   Objects that have been tagged, are tagged with an ObjectIndex,
  51  *   Objects that are not tagged need a ObjectIndex, a lookup when
  52  *     heap=sites, and a new one when heap=dump.
  53  *   Objects that are freed, need the tag converted to an ObjectIndex,
  54  *     so they can be freed, but only when heap=dump.
  55  *   The thread serial number is for the thread associated with this
  56  *     object. If the object is a Thread object, it should be the serial
  57  *     number for that thread. The ThreadStart event is responsible
  58  *     for making sure the thread serial number is correct, but between the
  59  *     initial allocation of a Thread object and it's ThreadStart event
  60  *     the thread serial number could be for the thread that allocated
  61  *     the Thread object.
  62  *
  63  * This will likely be the largest table when using heap=dump, when
  64  *   there is one table entry per object.
  65  *
  66  * ObjectIndex entries differ between heap=dump and heap=sites.
  67  *   With heap=sites, each ObjectIndex represents a unique site, size,
  68  *   and kind of object, so many jobject's will map to a single ObjectIndex.
  69  *   With heap=dump, every ObjectIndex maps to a unique jobject.
  70  *
  71  * During processing of a heap dump, the references for the object
  72  *   this ObjectIndex represents is assigned to the references field
  73  *   of the ObjectInfo as a linked list. (see hprof_references.c).
  74  *   Once all the refernces are attached, they are processed into the
  75  *   appropriate hprof dump information.
  76  *
  77  * The references field is set and cleared as many times as the heap
  78  *   is dumped, as is the reference table.
  79  *
  80  */
  81 
  82 #include "hprof.h"
  83 
  84 typedef struct ObjectKey {
  85     SiteIndex    site_index;    /* Site of allocation */
  86     jint         size;          /* Size of object as reported by VM */
  87     ObjectKind   kind;          /* Kind of object, most are OBJECT_NORMAL */
  88     SerialNumber serial_num;    /* For heap=dump, a unique number. */
  89 } ObjectKey;
  90 
  91 typedef struct ObjectInfo {
  92     RefIndex     references;        /* Linked list of refs in this object */
  93     SerialNumber thread_serial_num; /* Thread serial number for allocation */
  94 } ObjectInfo;
  95 
  96 /* Private internal functions. */
  97 
  98 static ObjectKey*
  99 get_pkey(ObjectIndex index)
 100 {
 101     void *key_ptr;
 102     int   key_len;
 103 
 104     table_get_key(gdata->object_table, index, (void*)&key_ptr, &key_len);
 105     HPROF_ASSERT(key_len==(int)sizeof(ObjectKey));
 106     HPROF_ASSERT(key_ptr!=NULL);
 107     return (ObjectKey*)key_ptr;
 108 }
 109 
 110 static ObjectInfo *
 111 get_info(ObjectIndex index)
 112 {
 113     ObjectInfo *info;
 114 
 115     info = (ObjectInfo*)table_get_info(gdata->object_table, index);
 116     return info;
 117 }
 118 
 119 static void
 120 list_item(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
 121 {
 122     ObjectKey  *pkey;
 123     ObjectInfo *info;
 124 
 125     HPROF_ASSERT(key_ptr!=NULL);
 126     HPROF_ASSERT(key_len!=0);
 127     HPROF_ASSERT(info_ptr!=NULL);
 128 
 129     info = (ObjectInfo*)info_ptr;
 130 
 131     pkey = (ObjectKey*)key_ptr;
 132     debug_message( "Object 0x%08x: site=0x%08x, SN=%u, "
 133                           " size=%d, kind=%d, refs=0x%x, threadSN=%u\n",
 134          i, pkey->site_index, pkey->serial_num, pkey->size, pkey->kind,
 135          info->references, info->thread_serial_num);
 136 }
 137 
 138 static void
 139 clear_references(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
 140 {
 141     ObjectInfo *info;
 142 
 143     HPROF_ASSERT(info_ptr!=NULL);
 144     info = (ObjectInfo *)info_ptr;
 145     info->references = 0;
 146 }
 147 
 148 static void
 149 dump_class_references(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
 150 {
 151     ObjectInfo *info;
 152 
 153     HPROF_ASSERT(info_ptr!=NULL);
 154     info = (ObjectInfo *)info_ptr;
 155     reference_dump_class((JNIEnv*)arg, i, info->references);
 156 }
 157 
 158 static void
 159 dump_instance_references(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
 160 {
 161     ObjectInfo *info;
 162 
 163     HPROF_ASSERT(info_ptr!=NULL);
 164     info = (ObjectInfo *)info_ptr;
 165     reference_dump_instance((JNIEnv*)arg, i, info->references);
 166 }
 167 
 168 /* External interfaces. */
 169 
 170 ObjectIndex
 171 object_new(SiteIndex site_index, jint size, ObjectKind kind, SerialNumber thread_serial_num)
 172 {
 173     ObjectIndex index;
 174     ObjectKey   key;
 175     static ObjectKey empty_key;
 176 
 177     key            = empty_key;
 178     key.site_index = site_index;
 179     key.size       = size;
 180     key.kind       = kind;
 181     if ( gdata->heap_dump ) {
 182         static ObjectInfo empty_info;
 183         ObjectInfo i;
 184 
 185         i = empty_info;
 186         i.thread_serial_num = thread_serial_num;
 187         key.serial_num = gdata->object_serial_number_counter++;
 188         index = table_create_entry(gdata->object_table,
 189                             &key, (int)sizeof(ObjectKey), &i);
 190     } else {
 191         key.serial_num =
 192              class_get_serial_number(site_get_class_index(site_index));
 193         index = table_find_or_create_entry(gdata->object_table,
 194                             &key, (int)sizeof(ObjectKey), NULL, NULL);
 195     }
 196     site_update_stats(site_index, size, 1);
 197     return index;
 198 }
 199 
 200 void
 201 object_init(void)
 202 {
 203     jint bucket_count;
 204 
 205     bucket_count = 511;
 206     if ( gdata->heap_dump ) {
 207         bucket_count = 0;
 208     }
 209     HPROF_ASSERT(gdata->object_table==NULL);
 210     gdata->object_table = table_initialize("Object", 4096,
 211                         4096, bucket_count, (int)sizeof(ObjectInfo));
 212 }
 213 
 214 SiteIndex
 215 object_get_site(ObjectIndex index)
 216 {
 217     ObjectKey *pkey;
 218 
 219     pkey = get_pkey(index);
 220     return pkey->site_index;
 221 }
 222 
 223 jint
 224 object_get_size(ObjectIndex index)
 225 {
 226     ObjectKey *pkey;
 227 
 228     pkey = get_pkey(index);
 229     return pkey->size;
 230 }
 231 
 232 ObjectKind
 233 object_get_kind(ObjectIndex index)
 234 {
 235     ObjectKey *pkey;
 236 
 237     pkey = get_pkey(index);
 238     return pkey->kind;
 239 }
 240 
 241 ObjectKind
 242 object_free(ObjectIndex index)
 243 {
 244     ObjectKey *pkey;
 245     ObjectKind kind;
 246 
 247     pkey = get_pkey(index);
 248     kind = pkey->kind;
 249 
 250     /* Decrement allocations at this site. */
 251     site_update_stats(pkey->site_index, -(pkey->size), -1);
 252 
 253     if ( gdata->heap_dump ) {
 254         table_free_entry(gdata->object_table, index);
 255     }
 256     return kind;
 257 }
 258 
 259 void
 260 object_list(void)
 261 {
 262     debug_message(
 263         "--------------------- Object Table ------------------------\n");
 264     table_walk_items(gdata->object_table, &list_item, NULL);
 265     debug_message(
 266         "----------------------------------------------------------\n");
 267 }
 268 
 269 void
 270 object_cleanup(void)
 271 {
 272     table_cleanup(gdata->object_table, NULL, NULL);
 273     gdata->object_table = NULL;
 274 }
 275 
 276 void
 277 object_set_thread_serial_number(ObjectIndex index,
 278                                 SerialNumber thread_serial_num)
 279 {
 280     ObjectInfo *info;
 281 
 282     info = get_info(index);
 283     info->thread_serial_num = thread_serial_num;
 284 }
 285 
 286 SerialNumber
 287 object_get_thread_serial_number(ObjectIndex index)
 288 {
 289     ObjectInfo *info;
 290 
 291     info = get_info(index);
 292     return info->thread_serial_num;
 293 }
 294 
 295 RefIndex
 296 object_get_references(ObjectIndex index)
 297 {
 298     ObjectInfo *info;
 299 
 300     info = get_info(index);
 301     return info->references;
 302 }
 303 
 304 void
 305 object_set_references(ObjectIndex index, RefIndex ref_index)
 306 {
 307     ObjectInfo *info;
 308 
 309     info = get_info(index);
 310     info->references = ref_index;
 311 }
 312 
 313 void
 314 object_clear_references(void)
 315 {
 316     table_walk_items(gdata->object_table, &clear_references, NULL);
 317 }
 318 
 319 void
 320 object_reference_dump(JNIEnv *env)
 321 {
 322     table_walk_items(gdata->object_table, &dump_instance_references, (void*)env);
 323     table_walk_items(gdata->object_table, &dump_class_references, (void*)env);
 324 }