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 }