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 references table (used in hprof_object.c). */ 42 43 /* 44 * This table is used by the object table to store object reference 45 * and primitive data information obtained from iterations over the 46 * heap (see hprof_site.c). 47 * 48 * Most of these table entries have no Key, but the key is used to store 49 * the primitive array and primitive field jvalue. None of these entries 50 * are ever looked up, there will be no hash table, use of the 51 * LookupTable was just an easy way to handle a unbounded table of 52 * entries. The object table (see hprof_object.c) will completely 53 * free this reference table after each heap dump or after processing the 54 * references and primitive data. 55 * 56 * The hprof format required this accumulation of all heap iteration 57 * references and primitive data from objects in order to compose an 58 * hprof records for it. 59 * 60 * This file contains detailed understandings of how an hprof CLASS 61 * and INSTANCE dump is constructed, most of this is derived from the 62 * original hprof code, but some has been derived by reading the HAT 63 * code that accepts this format. 64 * 65 */ 66 67 #include "hprof.h" 68 69 /* The flavor of data being saved in the RefInfo */ 70 enum { 71 INFO_OBJECT_REF_DATA = 1, 72 INFO_PRIM_FIELD_DATA = 2, 73 INFO_PRIM_ARRAY_DATA = 3 74 }; 75 76 /* Reference information, object reference or primitive data information */ 77 typedef struct RefInfo { 78 ObjectIndex object_index; /* If an object reference, the referree index */ 79 jint index; /* If array or field, array or field index */ 80 jint length; /* If array the element count, if not -1 */ 81 RefIndex next; /* The next table element */ 82 unsigned flavor : 8; /* INFO_*, flavor of RefInfo */ 83 unsigned refKind : 8; /* The kind of reference */ 84 unsigned primType : 8; /* If primitive data involved, it's type */ 85 } RefInfo; 86 87 /* Private internal functions. */ 88 89 /* Get the RefInfo structure from an entry */ 90 static RefInfo * 91 get_info(RefIndex index) 92 { 93 RefInfo *info; 94 95 info = (RefInfo*)table_get_info(gdata->reference_table, index); 96 return info; 97 } 98 99 /* Get a jvalue that was stored as the key. */ 100 static jvalue 101 get_key_value(RefIndex index) 102 { 103 void *key; 104 int len; 105 jvalue value; 106 static jvalue empty_value; 107 108 key = NULL; 109 table_get_key(gdata->reference_table, index, &key, &len); 110 HPROF_ASSERT(key!=NULL); 111 HPROF_ASSERT(len==(int)sizeof(jvalue)); 112 if ( key != NULL ) { 113 (void)memcpy(&value, key, (int)sizeof(jvalue)); 114 } else { 115 value = empty_value; 116 } 117 return value; 118 } 119 120 /* Get size of a primitive type */ 121 static jint 122 get_prim_size(jvmtiPrimitiveType primType) 123 { 124 jint size; 125 126 switch ( primType ) { 127 case JVMTI_PRIMITIVE_TYPE_BOOLEAN: 128 size = (jint)sizeof(jboolean); 129 break; 130 case JVMTI_PRIMITIVE_TYPE_BYTE: 131 size = (jint)sizeof(jbyte); 132 break; 133 case JVMTI_PRIMITIVE_TYPE_CHAR: 134 size = (jint)sizeof(jchar); 135 break; 136 case JVMTI_PRIMITIVE_TYPE_SHORT: 137 size = (jint)sizeof(jshort); 138 break; 139 case JVMTI_PRIMITIVE_TYPE_INT: 140 size = (jint)sizeof(jint); 141 break; 142 case JVMTI_PRIMITIVE_TYPE_FLOAT: 143 size = (jint)sizeof(jfloat); 144 break; 145 case JVMTI_PRIMITIVE_TYPE_LONG: 146 size = (jint)sizeof(jlong); 147 break; 148 case JVMTI_PRIMITIVE_TYPE_DOUBLE: 149 size = (jint)sizeof(jdouble); 150 break; 151 default: 152 HPROF_ASSERT(0); 153 size = 1; 154 break; 155 } 156 return size; 157 } 158 159 /* Get a void* elements array that was stored as the key. */ 160 static void * 161 get_key_elements(RefIndex index, jvmtiPrimitiveType primType, 162 jint *nelements, jint *nbytes) 163 { 164 void *key; 165 jint byteLen; 166 167 HPROF_ASSERT(nelements!=NULL); 168 HPROF_ASSERT(nbytes!=NULL); 169 170 table_get_key(gdata->reference_table, index, &key, &byteLen); 171 HPROF_ASSERT(byteLen>=0); 172 HPROF_ASSERT(byteLen!=0?key!=NULL:key==NULL); 173 *nbytes = byteLen; 174 *nelements = byteLen / get_prim_size(primType); 175 return key; 176 } 177 178 /* Dump a RefInfo* structure */ 179 static void 180 dump_ref_info(RefInfo *info) 181 { 182 debug_message("[%d]: flavor=%d" 183 ", refKind=%d" 184 ", primType=%d" 185 ", object_index=0x%x" 186 ", length=%d" 187 ", next=0x%x" 188 "\n", 189 info->index, 190 info->flavor, 191 info->refKind, 192 info->primType, 193 info->object_index, 194 info->length, 195 info->next); 196 } 197 198 /* Dump a RefIndex list */ 199 static void 200 dump_ref_list(RefIndex list) 201 { 202 RefInfo *info; 203 RefIndex index; 204 205 debug_message("\nFOLLOW REFERENCES RETURNED:\n"); 206 index = list; 207 while ( index != 0 ) { 208 info = get_info(index); 209 dump_ref_info(info); 210 index = info->next; 211 } 212 } 213 214 /* Dump information about a field and what ref data we had on it */ 215 static void 216 dump_field(FieldInfo *fields, jvalue *fvalues, int n_fields, 217 jint index, jvalue value, jvmtiPrimitiveType primType) 218 { 219 ClassIndex cnum; 220 StringIndex name; 221 StringIndex sig; 222 223 cnum = fields[index].cnum; 224 name = fields[index].name_index; 225 sig = fields[index].sig_index; 226 debug_message("[%d] %s \"%s\" \"%s\"", 227 index, 228 cnum!=0?string_get(class_get_signature(cnum)):"?", 229 name!=0?string_get(name):"?", 230 sig!=0?string_get(sig):"?"); 231 if ( fields[index].primType!=0 || fields[index].primType!=primType ) { 232 debug_message(" (primType=%d(%c)", 233 fields[index].primType, 234 primTypeToSigChar(fields[index].primType)); 235 if ( primType != fields[index].primType ) { 236 debug_message(", got %d(%c)", 237 primType, 238 primTypeToSigChar(primType)); 239 } 240 debug_message(")"); 241 } else { 242 debug_message("(ty=OBJ)"); 243 } 244 if ( value.j != (jlong)0 || fvalues[index].j != (jlong)0 ) { 245 debug_message(" val=[0x%08x,0x%08x] or [0x%08x,0x%08x]", 246 jlong_high(value.j), jlong_low(value.j), 247 jlong_high(fvalues[index].j), jlong_low(fvalues[index].j)); 248 } 249 debug_message("\n"); 250 } 251 252 /* Dump all the fields of interest */ 253 static void 254 dump_fields(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields) 255 { 256 int i; 257 258 debug_message("\nHPROF LIST OF ALL FIELDS:\n"); 259 for ( i = 0 ; i < n_fields ; i++ ) { 260 if ( fields[i].name_index != 0 ) { 261 dump_field(fields, fvalues, n_fields, i, fvalues[i], fields[i].primType); 262 } 263 } 264 dump_ref_list(list); 265 } 266 267 /* Verify field data */ 268 static void 269 verify_field(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields, 270 jint index, jvalue value, jvmtiPrimitiveType primType) 271 { 272 HPROF_ASSERT(fvalues != NULL); 273 HPROF_ASSERT(n_fields > 0); 274 HPROF_ASSERT(index < n_fields); 275 HPROF_ASSERT(index >= 0 ); 276 if ( primType!=fields[index].primType ) { 277 dump_fields(list, fields, fvalues, n_fields); 278 debug_message("\nPROBLEM WITH:\n"); 279 dump_field(fields, fvalues, n_fields, index, value, primType); 280 debug_message("\n"); 281 HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data"); 282 } 283 if ( primType == JVMTI_PRIMITIVE_TYPE_BOOLEAN && 284 ( value.b != 1 && value.b != 0 ) ) { 285 dump_fields(list, fields, fvalues, n_fields); 286 debug_message("\nPROBLEM WITH:\n"); 287 dump_field(fields, fvalues, n_fields, index, value, primType); 288 debug_message("\n"); 289 HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data"); 290 } 291 } 292 293 /* Fill in a field value, making sure the index is safe */ 294 static void 295 fill_in_field_value(RefIndex list, FieldInfo *fields, jvalue *fvalues, 296 int n_fields, jint index, jvalue value, 297 jvmtiPrimitiveType primType) 298 { 299 HPROF_ASSERT(fvalues != NULL); 300 HPROF_ASSERT(n_fields > 0); 301 HPROF_ASSERT(index < n_fields); 302 HPROF_ASSERT(index >= 0 ); 303 HPROF_ASSERT(fvalues[index].j==(jlong)0); 304 verify_field(list, fields, fvalues, n_fields, index, value, primType); 305 if (index >= 0 && index < n_fields) { 306 fvalues[index] = value; 307 } 308 } 309 310 /* Walk all references for an ObjectIndex and construct the hprof CLASS dump. */ 311 static void 312 dump_class_and_supers(JNIEnv *env, ObjectIndex object_index, RefIndex list) 313 { 314 SiteIndex site_index; 315 SerialNumber trace_serial_num; 316 RefIndex index; 317 ClassIndex super_cnum; 318 ObjectIndex super_index; 319 LoaderIndex loader_index; 320 ObjectIndex signers_index; 321 ObjectIndex domain_index; 322 FieldInfo *fields; 323 jvalue *fvalues; 324 jint n_fields; 325 jboolean skip_fields; 326 jint n_fields_set; 327 jlong size; 328 ClassIndex cnum; 329 char *sig; 330 ObjectKind kind; 331 TraceIndex trace_index; 332 Stack *cpool_values; 333 ConstantPoolValue *cpool; 334 jint cpool_count; 335 336 HPROF_ASSERT(object_index!=0); 337 kind = object_get_kind(object_index); 338 if ( kind != OBJECT_CLASS ) { 339 return; 340 } 341 site_index = object_get_site(object_index); 342 HPROF_ASSERT(site_index!=0); 343 cnum = site_get_class_index(site_index); 344 HPROF_ASSERT(cnum!=0); 345 if ( class_get_status(cnum) & CLASS_DUMPED ) { 346 return; 347 } 348 class_add_status(cnum, CLASS_DUMPED); 349 size = (jlong)object_get_size(object_index); 350 351 super_index = 0; 352 super_cnum = class_get_super(cnum); 353 if ( super_cnum != 0 ) { 354 super_index = class_get_object_index(super_cnum); 355 if ( super_index != 0 ) { 356 dump_class_and_supers(env, super_index, 357 object_get_references(super_index)); 358 } 359 } 360 361 trace_index = site_get_trace_index(site_index); 362 HPROF_ASSERT(trace_index!=0); 363 trace_serial_num = trace_get_serial_number(trace_index); 364 sig = string_get(class_get_signature(cnum)); 365 loader_index = class_get_loader(cnum); 366 signers_index = 0; 367 domain_index = 0; 368 369 /* Get field information */ 370 n_fields = 0; 371 skip_fields = JNI_FALSE; 372 n_fields_set = 0; 373 fields = NULL; 374 fvalues = NULL; 375 if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) { 376 /* Problems getting all the fields, can't trust field index values */ 377 skip_fields = JNI_TRUE; 378 /* Class with no references at all? (ok to be unprepared if list==0?) */ 379 if ( list != 0 ) { 380 /* It is assumed that the reason why we didn't get the fields 381 * was because the class is not prepared. 382 */ 383 if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) { 384 dump_ref_list(list); 385 debug_message("Unprepared class with references: %s\n", 386 sig); 387 } 388 HPROF_ERROR(JNI_FALSE, "Trouble with unprepared classes"); 389 } 390 /* Why would an unprepared class contain references? */ 391 } 392 if ( n_fields > 0 ) { 393 fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue)); 394 (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue)); 395 } 396 397 /* We use a Stack just because it will automatically expand as needed */ 398 cpool_values = stack_init(16, 16, sizeof(ConstantPoolValue)); 399 cpool = NULL; 400 cpool_count = 0; 401 402 index = list; 403 while ( index != 0 ) { 404 RefInfo *info; 405 jvalue ovalue; 406 static jvalue empty_value; 407 408 info = get_info(index); 409 410 switch ( info->flavor ) { 411 case INFO_OBJECT_REF_DATA: 412 switch ( info->refKind ) { 413 case JVMTI_HEAP_REFERENCE_FIELD: 414 case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: 415 /* Should never be seen on a class dump */ 416 HPROF_ASSERT(0); 417 break; 418 case JVMTI_HEAP_REFERENCE_STATIC_FIELD: 419 if ( skip_fields == JNI_TRUE ) { 420 break; 421 } 422 ovalue = empty_value; 423 ovalue.i = info->object_index; 424 fill_in_field_value(list, fields, fvalues, n_fields, 425 info->index, ovalue, 0); 426 n_fields_set++; 427 HPROF_ASSERT(n_fields_set <= n_fields); 428 break; 429 case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: { 430 ConstantPoolValue cpv; 431 ObjectIndex cp_object_index; 432 SiteIndex cp_site_index; 433 ClassIndex cp_cnum; 434 435 cp_object_index = info->object_index; 436 HPROF_ASSERT(cp_object_index!=0); 437 cp_site_index = object_get_site(cp_object_index); 438 HPROF_ASSERT(cp_site_index!=0); 439 cp_cnum = site_get_class_index(cp_site_index); 440 cpv.constant_pool_index = info->index; 441 cpv.sig_index = class_get_signature(cp_cnum); 442 cpv.value.i = cp_object_index; 443 stack_push(cpool_values, (void*)&cpv); 444 cpool_count++; 445 break; 446 } 447 case JVMTI_HEAP_REFERENCE_SIGNERS: 448 signers_index = info->object_index; 449 break; 450 case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN: 451 domain_index = info->object_index; 452 break; 453 case JVMTI_HEAP_REFERENCE_CLASS_LOADER: 454 case JVMTI_HEAP_REFERENCE_INTERFACE: 455 default: 456 /* Ignore, not needed */ 457 break; 458 } 459 break; 460 case INFO_PRIM_FIELD_DATA: 461 if ( skip_fields == JNI_TRUE ) { 462 break; 463 } 464 HPROF_ASSERT(info->primType!=0); 465 HPROF_ASSERT(info->length==-1); 466 HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_STATIC_FIELD); 467 ovalue = get_key_value(index); 468 fill_in_field_value(list, fields, fvalues, n_fields, 469 info->index, ovalue, info->primType); 470 n_fields_set++; 471 HPROF_ASSERT(n_fields_set <= n_fields); 472 break; 473 case INFO_PRIM_ARRAY_DATA: 474 default: 475 /* Should never see these */ 476 HPROF_ASSERT(0); 477 break; 478 } 479 480 index = info->next; 481 } 482 483 /* Get constant pool data if we have any */ 484 HPROF_ASSERT(cpool_count==stack_depth(cpool_values)); 485 if ( cpool_count > 0 ) { 486 cpool = (ConstantPoolValue*)stack_element(cpool_values, 0); 487 } 488 io_heap_class_dump(cnum, sig, object_index, trace_serial_num, 489 super_index, 490 loader_object_index(env, loader_index), 491 signers_index, domain_index, 492 (jint)size, cpool_count, cpool, n_fields, fields, fvalues); 493 494 stack_term(cpool_values); 495 if ( fvalues != NULL ) { 496 HPROF_FREE(fvalues); 497 } 498 } 499 500 /* Walk all references for an ObjectIndex and construct the hprof INST dump. */ 501 static void 502 dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list) 503 { 504 jvmtiPrimitiveType primType; 505 SiteIndex site_index; 506 SerialNumber trace_serial_num; 507 RefIndex index; 508 ObjectIndex class_index; 509 jlong size; 510 ClassIndex cnum; 511 char *sig; 512 void *elements; 513 jint num_elements; 514 jint num_bytes; 515 ObjectIndex *values; 516 FieldInfo *fields; 517 jvalue *fvalues; 518 jint n_fields; 519 jboolean skip_fields; 520 jint n_fields_set; 521 ObjectKind kind; 522 TraceIndex trace_index; 523 jboolean is_array; 524 jboolean is_prim_array; 525 526 HPROF_ASSERT(object_index!=0); 527 kind = object_get_kind(object_index); 528 if ( kind == OBJECT_CLASS ) { 529 return; 530 } 531 site_index = object_get_site(object_index); 532 HPROF_ASSERT(site_index!=0); 533 cnum = site_get_class_index(site_index); 534 HPROF_ASSERT(cnum!=0); 535 size = (jlong)object_get_size(object_index); 536 trace_index = site_get_trace_index(site_index); 537 HPROF_ASSERT(trace_index!=0); 538 trace_serial_num = trace_get_serial_number(trace_index); 539 sig = string_get(class_get_signature(cnum)); 540 class_index = class_get_object_index(cnum); 541 542 values = NULL; 543 elements = NULL; 544 num_elements = 0; 545 num_bytes = 0; 546 547 n_fields = 0; 548 skip_fields = JNI_FALSE; 549 n_fields_set = 0; 550 fields = NULL; 551 fvalues = NULL; 552 553 index = list; 554 555 is_array = JNI_FALSE; 556 is_prim_array = JNI_FALSE; 557 558 if ( sig[0] != JVM_SIGNATURE_ARRAY ) { 559 if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) { 560 /* Trouble getting all the fields, can't trust field index values */ 561 skip_fields = JNI_TRUE; 562 /* It is assumed that the reason why we didn't get the fields 563 * was because the class is not prepared. 564 */ 565 if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) { 566 if ( list != 0 ) { 567 dump_ref_list(list); 568 debug_message("Instance of unprepared class with refs: %s\n", 569 sig); 570 } else { 571 debug_message("Instance of unprepared class without refs: %s\n", 572 sig); 573 } 574 HPROF_ERROR(JNI_FALSE, "Big Trouble with unprepared class instances"); 575 } 576 } 577 if ( n_fields > 0 ) { 578 fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue)); 579 (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue)); 580 } 581 } else { 582 is_array = JNI_TRUE; 583 if ( sig[0] != 0 && sigToPrimSize(sig+1) != 0 ) { 584 is_prim_array = JNI_TRUE; 585 } 586 } 587 588 while ( index != 0 ) { 589 RefInfo *info; 590 jvalue ovalue; 591 static jvalue empty_value; 592 593 info = get_info(index); 594 595 /* Process reference objects, many not used right now. */ 596 switch ( info->flavor ) { 597 case INFO_OBJECT_REF_DATA: 598 switch ( info->refKind ) { 599 case JVMTI_HEAP_REFERENCE_SIGNERS: 600 case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN: 601 case JVMTI_HEAP_REFERENCE_CLASS_LOADER: 602 case JVMTI_HEAP_REFERENCE_INTERFACE: 603 case JVMTI_HEAP_REFERENCE_STATIC_FIELD: 604 case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: 605 /* Should never be seen on an instance dump */ 606 HPROF_ASSERT(0); 607 break; 608 case JVMTI_HEAP_REFERENCE_FIELD: 609 if ( skip_fields == JNI_TRUE ) { 610 break; 611 } 612 HPROF_ASSERT(is_array!=JNI_TRUE); 613 ovalue = empty_value; 614 ovalue.i = info->object_index; 615 fill_in_field_value(list, fields, fvalues, n_fields, 616 info->index, ovalue, 0); 617 n_fields_set++; 618 HPROF_ASSERT(n_fields_set <= n_fields); 619 break; 620 case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: 621 /* We get each object element one at a time. */ 622 HPROF_ASSERT(is_array==JNI_TRUE); 623 HPROF_ASSERT(is_prim_array!=JNI_TRUE); 624 if ( num_elements <= info->index ) { 625 int nbytes; 626 627 if ( values == NULL ) { 628 num_elements = info->index + 1; 629 nbytes = num_elements*(int)sizeof(ObjectIndex); 630 values = (ObjectIndex*)HPROF_MALLOC(nbytes); 631 (void)memset(values, 0, nbytes); 632 } else { 633 void *new_values; 634 int new_size; 635 int obytes; 636 637 obytes = num_elements*(int)sizeof(ObjectIndex); 638 new_size = info->index + 1; 639 nbytes = new_size*(int)sizeof(ObjectIndex); 640 new_values = (void*)HPROF_MALLOC(nbytes); 641 (void)memcpy(new_values, values, obytes); 642 (void)memset(((char*)new_values)+obytes, 0, 643 nbytes-obytes); 644 HPROF_FREE(values); 645 num_elements = new_size; 646 values = new_values; 647 } 648 } 649 HPROF_ASSERT(values[info->index]==0); 650 values[info->index] = info->object_index; 651 break; 652 default: 653 /* Ignore, not needed */ 654 break; 655 } 656 break; 657 case INFO_PRIM_FIELD_DATA: 658 if ( skip_fields == JNI_TRUE ) { 659 break; 660 } 661 HPROF_ASSERT(info->primType!=0); 662 HPROF_ASSERT(info->length==-1); 663 HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_FIELD); 664 HPROF_ASSERT(is_array!=JNI_TRUE); 665 ovalue = get_key_value(index); 666 fill_in_field_value(list, fields, fvalues, n_fields, 667 info->index, ovalue, info->primType); 668 n_fields_set++; 669 HPROF_ASSERT(n_fields_set <= n_fields); 670 break; 671 case INFO_PRIM_ARRAY_DATA: 672 /* Should only be one, and it's handled below */ 673 HPROF_ASSERT(info->refKind==0); 674 /* We assert that nothing else was saved with this array */ 675 HPROF_ASSERT(index==list&&info->next==0); 676 HPROF_ASSERT(is_array==JNI_TRUE); 677 HPROF_ASSERT(is_prim_array==JNI_TRUE); 678 primType = info->primType; 679 elements = get_key_elements(index, primType, 680 &num_elements, &num_bytes); 681 HPROF_ASSERT(info->length==num_elements); 682 size = num_bytes; 683 break; 684 default: 685 HPROF_ASSERT(0); 686 break; 687 } 688 index = info->next; 689 } 690 691 if ( is_array == JNI_TRUE ) { 692 if ( is_prim_array == JNI_TRUE ) { 693 HPROF_ASSERT(values==NULL); 694 io_heap_prim_array(object_index, trace_serial_num, 695 (jint)size, num_elements, sig, elements); 696 } else { 697 HPROF_ASSERT(elements==NULL); 698 io_heap_object_array(object_index, trace_serial_num, 699 (jint)size, num_elements, sig, values, class_index); 700 } 701 } else { 702 io_heap_instance_dump(cnum, object_index, trace_serial_num, 703 class_index, (jint)size, sig, fields, fvalues, n_fields); 704 } 705 if ( values != NULL ) { 706 HPROF_FREE(values); 707 } 708 if ( fvalues != NULL ) { 709 HPROF_FREE(fvalues); 710 } 711 if ( elements != NULL ) { 712 /* Do NOT free elements, it's a key in the table, leave it be */ 713 } 714 } 715 716 /* External interfaces. */ 717 718 void 719 reference_init(void) 720 { 721 HPROF_ASSERT(gdata->reference_table==NULL); 722 gdata->reference_table = table_initialize("Ref", 2048, 4096, 0, 723 (int)sizeof(RefInfo)); 724 } 725 726 /* Save away a reference to an object */ 727 RefIndex 728 reference_obj(RefIndex next, jvmtiHeapReferenceKind refKind, 729 ObjectIndex object_index, jint index, jint length) 730 { 731 static RefInfo empty_info; 732 RefIndex entry; 733 RefInfo info; 734 735 info = empty_info; 736 info.flavor = INFO_OBJECT_REF_DATA; 737 info.refKind = refKind; 738 info.object_index = object_index; 739 info.index = index; 740 info.length = length; 741 info.next = next; 742 entry = table_create_entry(gdata->reference_table, NULL, 0, (void*)&info); 743 return entry; 744 } 745 746 /* Save away some primitive field data */ 747 RefIndex 748 reference_prim_field(RefIndex next, jvmtiHeapReferenceKind refKind, 749 jvmtiPrimitiveType primType, jvalue field_value, jint field_index) 750 { 751 static RefInfo empty_info; 752 RefIndex entry; 753 RefInfo info; 754 755 HPROF_ASSERT(primType==JVMTI_PRIMITIVE_TYPE_BOOLEAN?(field_value.b==1||field_value.b==0):1); 756 757 info = empty_info; 758 info.flavor = INFO_PRIM_FIELD_DATA; 759 info.refKind = refKind; 760 info.primType = primType; 761 info.index = field_index; 762 info.length = -1; 763 info.next = next; 764 entry = table_create_entry(gdata->reference_table, 765 (void*)&field_value, (int)sizeof(jvalue), (void*)&info); 766 return entry; 767 } 768 769 /* Save away some primitive array data */ 770 RefIndex 771 reference_prim_array(RefIndex next, jvmtiPrimitiveType primType, 772 const void *elements, jint elementCount) 773 { 774 static RefInfo empty_info; 775 RefIndex entry; 776 RefInfo info; 777 778 HPROF_ASSERT(next == 0); 779 HPROF_ASSERT(elementCount >= 0); 780 HPROF_ASSERT(elements != NULL); 781 782 info = empty_info; 783 info.flavor = INFO_PRIM_ARRAY_DATA; 784 info.refKind = 0; 785 info.primType = primType; 786 info.index = 0; 787 info.length = elementCount; 788 info.next = next; 789 entry = table_create_entry(gdata->reference_table, (void*)elements, 790 elementCount * get_prim_size(primType), (void*)&info); 791 return entry; 792 } 793 794 void 795 reference_cleanup(void) 796 { 797 if ( gdata->reference_table == NULL ) { 798 return; 799 } 800 table_cleanup(gdata->reference_table, NULL, NULL); 801 gdata->reference_table = NULL; 802 } 803 804 void 805 reference_dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list) 806 { 807 dump_instance(env, object_index, list); 808 } 809 810 void 811 reference_dump_class(JNIEnv *env, ObjectIndex object_index, RefIndex list) 812 { 813 dump_class_and_supers(env, object_index, list); 814 }