Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/jvmti/hprof/hprof_site.c
38829 views
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
}
906
907