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_class.c
38829 views
1
/*
2
* Copyright (c) 2003, 2013, 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
/* Table of class information.
42
*
43
* Each element in this table is identified with a ClassIndex.
44
* Each element is uniquely identified by it's signature and loader.
45
* Every class load has a unique class serial number.
46
* While loaded, each element will have a cache of a global reference
47
* to it's jclass object, plus jmethodID's as needed.
48
* Method signatures and names are obtained via BCI.
49
* Methods can be identified with a ClassIndex and MethodIndex pair,
50
* where the MethodIndex matches the index of the method name and
51
* signature arrays obtained from the BCI pass.
52
* Strings are stored in the string table and a StringIndex is used.
53
* Class Loaders are stored in the loader table and a LoaderIndex is used.
54
* Since the jclass object is an object, at some point an object table
55
* entry may be allocated for the jclass as an ObjectIndex.
56
*/
57
58
#include "hprof.h"
59
60
/* Effectively represents a jclass object. */
61
62
/* These table elements are made unique by and sorted by signature name. */
63
64
typedef struct ClassKey {
65
StringIndex sig_string_index; /* Signature of class */
66
LoaderIndex loader_index; /* Index for class loader */
67
} ClassKey;
68
69
/* Each class could contain method information, gotten from BCI callback */
70
71
typedef struct MethodInfo {
72
StringIndex name_index; /* Method name, index into string table */
73
StringIndex sig_index; /* Method signature, index into string table */
74
jmethodID method_id; /* Method ID, possibly NULL at first */
75
} MethodInfo;
76
77
/* The basic class information we save */
78
79
typedef struct ClassInfo {
80
jclass classref; /* Global ref to jclass */
81
MethodInfo *method; /* Array of method data */
82
int method_count; /* Count of methods */
83
ObjectIndex object_index; /* Optional object index for jclass */
84
SerialNumber serial_num; /* Unique to the actual class load */
85
ClassStatus status; /* Current class status (bit mask) */
86
ClassIndex super; /* Super class in this table */
87
StringIndex name; /* Name of class */
88
jint inst_size; /* #bytes needed for instance fields */
89
jint field_count; /* Number of all fields */
90
FieldInfo *field; /* Pointer to all FieldInfo's */
91
} ClassInfo;
92
93
/* Private interfaces */
94
95
static ClassKey*
96
get_pkey(ClassIndex index)
97
{
98
void *key_ptr;
99
int key_len;
100
101
table_get_key(gdata->class_table, index, (void*)&key_ptr, &key_len);
102
HPROF_ASSERT(key_len==sizeof(ClassKey));
103
HPROF_ASSERT(key_ptr!=NULL);
104
return (ClassKey*)key_ptr;
105
}
106
107
static void
108
fillin_pkey(const char *sig, LoaderIndex loader_index, ClassKey *pkey)
109
{
110
static ClassKey empty_key;
111
112
HPROF_ASSERT(loader_index!=0);
113
*pkey = empty_key;
114
pkey->sig_string_index = string_find_or_create(sig);
115
pkey->loader_index = loader_index;
116
}
117
118
static ClassInfo *
119
get_info(ClassIndex index)
120
{
121
ClassInfo *info;
122
123
info = (ClassInfo*)table_get_info(gdata->class_table, index);
124
return info;
125
}
126
127
static void
128
fill_info(TableIndex index, ClassKey *pkey)
129
{
130
ClassInfo *info;
131
char *sig;
132
133
info = get_info(index);
134
info->serial_num = gdata->class_serial_number_counter++;
135
info->method_count = 0;
136
info->inst_size = -1;
137
info->field_count = -1;
138
info->field = NULL;
139
sig = string_get(pkey->sig_string_index);
140
if ( sig[0] != JVM_SIGNATURE_CLASS ) {
141
info->name = pkey->sig_string_index;
142
} else {
143
int len;
144
145
len = string_get_len(pkey->sig_string_index);
146
if ( len > 2 ) {
147
char *name;
148
149
/* Class signature looks like "Lname;", we want "name" here. */
150
name = HPROF_MALLOC(len-1);
151
(void)memcpy(name, sig+1, len-2);
152
name[len-2] = 0;
153
info->name = string_find_or_create(name);
154
HPROF_FREE(name);
155
} else {
156
/* This would be strange, a class signature not in "Lname;" form? */
157
info->name = pkey->sig_string_index;
158
}
159
}
160
}
161
162
static ClassIndex
163
find_entry(ClassKey *pkey)
164
{
165
ClassIndex index;
166
167
index = table_find_entry(gdata->class_table,
168
(void*)pkey, (int)sizeof(ClassKey));
169
return index;
170
}
171
172
static ClassIndex
173
create_entry(ClassKey *pkey)
174
{
175
ClassIndex index;
176
177
index = table_create_entry(gdata->class_table,
178
(void*)pkey, (int)sizeof(ClassKey), NULL);
179
fill_info(index, pkey);
180
return index;
181
}
182
183
static ClassIndex
184
find_or_create_entry(ClassKey *pkey)
185
{
186
ClassIndex index;
187
188
HPROF_ASSERT(pkey!=NULL);
189
HPROF_ASSERT(pkey->loader_index!=0);
190
index = find_entry(pkey);
191
if ( index == 0 ) {
192
index = create_entry(pkey);
193
}
194
return index;
195
}
196
197
static void
198
delete_classref(JNIEnv *env, ClassInfo *info, jclass klass)
199
{
200
jclass ref;
201
int i;
202
203
HPROF_ASSERT(env!=NULL);
204
HPROF_ASSERT(info!=NULL);
205
206
for ( i = 0 ; i < info->method_count ; i++ ) {
207
info->method[i].method_id = NULL;
208
}
209
ref = info->classref;
210
if ( klass != NULL ) {
211
info->classref = newGlobalReference(env, klass);
212
} else {
213
info->classref = NULL;
214
}
215
if ( ref != NULL ) {
216
deleteGlobalReference(env, ref);
217
}
218
}
219
220
static void
221
cleanup_item(TableIndex index, void *key_ptr, int key_len,
222
void *info_ptr, void *arg)
223
{
224
ClassInfo *info;
225
226
/* Cleanup any information in this ClassInfo structure. */
227
HPROF_ASSERT(key_ptr!=NULL);
228
HPROF_ASSERT(key_len==sizeof(ClassKey));
229
HPROF_ASSERT(info_ptr!=NULL);
230
info = (ClassInfo *)info_ptr;
231
if ( info->method_count > 0 ) {
232
HPROF_FREE((void*)info->method);
233
info->method_count = 0;
234
info->method = NULL;
235
}
236
if ( info->field != NULL ) {
237
HPROF_FREE((void*)info->field);
238
info->field_count = 0;
239
info->field = NULL;
240
}
241
}
242
243
static void
244
delete_ref_item(TableIndex index, void *key_ptr, int key_len,
245
void *info_ptr, void *arg)
246
{
247
delete_classref((JNIEnv*)arg, (ClassInfo*)info_ptr, NULL);
248
}
249
250
static void
251
list_item(TableIndex index, void *key_ptr, int key_len,
252
void *info_ptr, void *arg)
253
{
254
ClassInfo *info;
255
ClassKey key;
256
char *sig;
257
int i;
258
259
HPROF_ASSERT(key_ptr!=NULL);
260
HPROF_ASSERT(key_len==sizeof(ClassKey));
261
HPROF_ASSERT(info_ptr!=NULL);
262
key = *((ClassKey*)key_ptr);
263
sig = string_get(key.sig_string_index);
264
info = (ClassInfo *)info_ptr;
265
debug_message(
266
"0x%08x: Class %s, SN=%u, status=0x%08x, ref=%p,"
267
" method_count=%d\n",
268
index,
269
(const char *)sig,
270
info->serial_num,
271
info->status,
272
(void*)info->classref,
273
info->method_count);
274
if ( info->method_count > 0 ) {
275
for ( i = 0 ; i < info->method_count ; i++ ) {
276
debug_message(
277
" Method %d: \"%s\", sig=\"%s\", method=%p\n",
278
i,
279
string_get(info->method[i].name_index),
280
string_get(info->method[i].sig_index),
281
(void*)info->method[i].method_id);
282
}
283
}
284
}
285
286
static void
287
all_status_remove(TableIndex index, void *key_ptr, int key_len,
288
void *info_ptr, void *arg)
289
{
290
ClassInfo *info;
291
ClassStatus status;
292
293
HPROF_ASSERT(info_ptr!=NULL);
294
/*LINTED*/
295
status = (ClassStatus)(long)(ptrdiff_t)arg;
296
info = (ClassInfo *)info_ptr;
297
info->status &= (~status);
298
}
299
300
static void
301
unload_walker(TableIndex index, void *key_ptr, int key_len,
302
void *info_ptr, void *arg)
303
{
304
ClassInfo *info;
305
306
HPROF_ASSERT(info_ptr!=NULL);
307
info = (ClassInfo *)info_ptr;
308
if ( ! ( info->status & CLASS_IN_LOAD_LIST ) ) {
309
if ( ! (info->status & (CLASS_SPECIAL|CLASS_SYSTEM|CLASS_UNLOADED)) ) {
310
io_write_class_unload(info->serial_num, info->object_index);
311
info->status |= CLASS_UNLOADED;
312
delete_classref((JNIEnv*)arg, info, NULL);
313
}
314
}
315
}
316
317
/* External interfaces */
318
319
void
320
class_init(void)
321
{
322
HPROF_ASSERT(gdata->class_table==NULL);
323
gdata->class_table = table_initialize("Class", 512, 512, 511,
324
(int)sizeof(ClassInfo));
325
}
326
327
ClassIndex
328
class_find_or_create(const char *sig, LoaderIndex loader_index)
329
{
330
ClassKey key;
331
332
fillin_pkey(sig, loader_index, &key);
333
return find_or_create_entry(&key);
334
}
335
336
ClassIndex
337
class_create(const char *sig, LoaderIndex loader_index)
338
{
339
ClassKey key;
340
341
fillin_pkey(sig, loader_index, &key);
342
return create_entry(&key);
343
}
344
345
void
346
class_prime_system_classes(void)
347
{
348
/* Prime System classes? Anything before VM_START is System class.
349
* Or classes loaded before env arg is non-NULL.
350
* Or any of the classes listed below.
351
*/
352
static const char * signatures[] =
353
{
354
"Ljava/lang/Object;",
355
"Ljava/io/Serializable;",
356
"Ljava/lang/String;",
357
"Ljava/lang/Class;",
358
"Ljava/lang/ClassLoader;",
359
"Ljava/lang/System;",
360
"Ljava/lang/Thread;",
361
"Ljava/lang/ThreadGroup;",
362
};
363
int n_signatures;
364
int i;
365
LoaderIndex loader_index;
366
367
n_signatures = (int)sizeof(signatures)/(int)sizeof(signatures[0]);
368
loader_index = loader_find_or_create(NULL, NULL);
369
for ( i = 0 ; i < n_signatures ; i++ ) {
370
ClassInfo *info;
371
ClassIndex index;
372
ClassKey key;
373
374
fillin_pkey(signatures[i], loader_index, &key);
375
index = find_or_create_entry(&key);
376
info = get_info(index);
377
info->status |= CLASS_SYSTEM;
378
}
379
}
380
381
void
382
class_add_status(ClassIndex index, ClassStatus status)
383
{
384
ClassInfo *info;
385
386
info = get_info(index);
387
info->status |= status;
388
}
389
390
ClassStatus
391
class_get_status(ClassIndex index)
392
{
393
ClassInfo *info;
394
395
info = get_info(index);
396
return info->status;
397
}
398
399
StringIndex
400
class_get_signature(ClassIndex index)
401
{
402
ClassKey *pkey;
403
404
pkey = get_pkey(index);
405
return pkey->sig_string_index;
406
}
407
408
SerialNumber
409
class_get_serial_number(ClassIndex index)
410
{
411
ClassInfo *info;
412
413
if ( index == 0 ) {
414
return 0;
415
}
416
info = get_info(index);
417
return info->serial_num;
418
}
419
420
void
421
class_all_status_remove(ClassStatus status)
422
{
423
table_walk_items(gdata->class_table, &all_status_remove,
424
(void*)(ptrdiff_t)(long)status);
425
}
426
427
void
428
class_do_unloads(JNIEnv *env)
429
{
430
table_walk_items(gdata->class_table, &unload_walker, (void*)env);
431
}
432
433
void
434
class_list(void)
435
{
436
debug_message(
437
"--------------------- Class Table ------------------------\n");
438
table_walk_items(gdata->class_table, &list_item, NULL);
439
debug_message(
440
"----------------------------------------------------------\n");
441
}
442
443
void
444
class_cleanup(void)
445
{
446
table_cleanup(gdata->class_table, &cleanup_item, NULL);
447
gdata->class_table = NULL;
448
}
449
450
void
451
class_delete_global_references(JNIEnv* env)
452
{
453
table_walk_items(gdata->class_table, &delete_ref_item, (void*)env);
454
}
455
456
void
457
class_set_methods(ClassIndex index, const char **name, const char **sig,
458
int count)
459
{
460
ClassInfo *info;
461
int i;
462
463
info = get_info(index);
464
if ( info->method_count > 0 ) {
465
HPROF_FREE((void*)info->method);
466
info->method_count = 0;
467
info->method = NULL;
468
}
469
info->method_count = count;
470
if ( count > 0 ) {
471
info->method = (MethodInfo *)HPROF_MALLOC(count*(int)sizeof(MethodInfo));
472
for ( i = 0 ; i < count ; i++ ) {
473
info->method[i].name_index = string_find_or_create(name[i]);
474
info->method[i].sig_index = string_find_or_create(sig[i]);
475
info->method[i].method_id = NULL;
476
}
477
}
478
}
479
480
jclass
481
class_new_classref(JNIEnv *env, ClassIndex index, jclass classref)
482
{
483
ClassInfo *info;
484
485
HPROF_ASSERT(classref!=NULL);
486
info = get_info(index);
487
if ( ! isSameObject(env, classref, info->classref) ) {
488
delete_classref(env, info, classref);
489
}
490
return info->classref;
491
}
492
493
jclass
494
class_get_class(JNIEnv *env, ClassIndex index)
495
{
496
ClassInfo *info;
497
jclass clazz;
498
499
info = get_info(index);
500
clazz = info->classref;
501
if ( env != NULL && clazz == NULL ) {
502
WITH_LOCAL_REFS(env, 1) {
503
jclass new_clazz;
504
char *class_name;
505
506
class_name = string_get(info->name);
507
/* This really only makes sense for the bootclass classes,
508
* since FindClass doesn't provide a way to load a class in
509
* a specific class loader.
510
*/
511
new_clazz = findClass(env, class_name);
512
if ( new_clazz == NULL ) {
513
HPROF_ERROR(JNI_TRUE, "Cannot load class with findClass");
514
}
515
HPROF_ASSERT(new_clazz!=NULL);
516
clazz = class_new_classref(env, index, new_clazz);
517
} END_WITH_LOCAL_REFS;
518
HPROF_ASSERT(clazz!=NULL);
519
}
520
return clazz;
521
}
522
523
jmethodID
524
class_get_methodID(JNIEnv *env, ClassIndex index, MethodIndex mnum)
525
{
526
ClassInfo *info;
527
jmethodID method;
528
529
info = get_info(index);
530
if (mnum >= info->method_count) {
531
jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
532
if ((*env)->ExceptionCheck(env)) {
533
(*env)->ExceptionClear(env);
534
HPROF_ERROR(JNI_TRUE,
535
"Could not find the java/lang/IllegalArgumentException class");
536
}
537
(*env)->ThrowNew(env, newExcCls, "Illegal mnum");
538
539
return NULL;
540
}
541
method = info->method[mnum].method_id;
542
if ( method == NULL ) {
543
char * name;
544
char * sig;
545
jclass clazz;
546
547
name = (char *)string_get(info->method[mnum].name_index);
548
if (name==NULL) {
549
jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
550
if ((*env)->ExceptionCheck(env)) {
551
(*env)->ExceptionClear(env);
552
HPROF_ERROR(JNI_TRUE,
553
"Could not find the java/lang/IllegalArgumentException class");
554
}
555
(*env)->ThrowNew(env, newExcCls, "Name not found");
556
557
return NULL;
558
}
559
sig = (char *)string_get(info->method[mnum].sig_index);
560
HPROF_ASSERT(sig!=NULL);
561
clazz = class_get_class(env, index);
562
if ( clazz != NULL ) {
563
method = getMethodID(env, clazz, name, sig);
564
HPROF_ASSERT(method!=NULL);
565
info = get_info(index);
566
info->method[mnum].method_id = method;
567
}
568
}
569
return method;
570
}
571
572
void
573
class_set_inst_size(ClassIndex index, jint inst_size)
574
{
575
ClassInfo *info;
576
577
info = get_info(index);
578
info->inst_size = inst_size;
579
}
580
581
jint
582
class_get_inst_size(ClassIndex index)
583
{
584
ClassInfo *info;
585
586
info = get_info(index);
587
return info->inst_size;
588
}
589
590
void
591
class_set_object_index(ClassIndex index, ObjectIndex object_index)
592
{
593
ClassInfo *info;
594
595
info = get_info(index);
596
info->object_index = object_index;
597
}
598
599
ObjectIndex
600
class_get_object_index(ClassIndex index)
601
{
602
ClassInfo *info;
603
604
info = get_info(index);
605
return info->object_index;
606
}
607
608
ClassIndex
609
class_get_super(ClassIndex index)
610
{
611
ClassInfo *info;
612
613
info = get_info(index);
614
return info->super;
615
}
616
617
void
618
class_set_super(ClassIndex index, ClassIndex super)
619
{
620
ClassInfo *info;
621
622
info = get_info(index);
623
info->super = super;
624
}
625
626
LoaderIndex
627
class_get_loader(ClassIndex index)
628
{
629
ClassKey *pkey;
630
631
pkey = get_pkey(index);
632
HPROF_ASSERT(pkey->loader_index!=0);
633
return pkey->loader_index;
634
}
635
636
/* Get ALL class fields (supers too), return 1 on error, 0 if ok */
637
jint
638
class_get_all_fields(JNIEnv *env, ClassIndex index,
639
jint *pfield_count, FieldInfo **pfield)
640
{
641
ClassInfo *info;
642
FieldInfo *finfo;
643
jint count;
644
jint ret;
645
646
count = 0;
647
finfo = NULL;
648
ret = 1; /* Default is to return an error condition */
649
650
info = get_info(index);
651
if ( info != NULL ) {
652
if ( info->field_count >= 0 ) {
653
/* Get cache */
654
count = info->field_count;
655
finfo = info->field;
656
ret = 0; /* Return of cache data, no error */
657
} else {
658
jclass klass;
659
660
klass = info->classref;
661
if ( klass == NULL || isSameObject(env, klass, NULL) ) {
662
/* This is probably an error because this will cause the field
663
* index values to be off, but I'm hesitant to generate a
664
* fatal error here, so I will issue something and continue.
665
* I should have been holding a global reference to all the
666
* jclass, so I'm not sure how this could happen.
667
* Issuing a FindClass() here is just asking for trouble
668
* because if the class went away, we aren't even sure
669
* what ClassLoader to use.
670
*/
671
HPROF_ERROR(JNI_FALSE, "Missing jclass when fields needed");
672
} else {
673
jint status;
674
675
status = getClassStatus(klass);
676
if ( status &
677
(JVMTI_CLASS_STATUS_PRIMITIVE|JVMTI_CLASS_STATUS_ARRAY) ) {
678
/* Set cache */
679
info->field_count = count;
680
info->field = finfo;
681
ret = 0; /* Primitive or array ok */
682
} else if ( status & JVMTI_CLASS_STATUS_PREPARED ) {
683
/* Call JVMTI to get them */
684
getAllClassFieldInfo(env, klass, &count, &finfo);
685
/* Set cache */
686
info->field_count = count;
687
info->field = finfo;
688
ret = 0;
689
}
690
}
691
}
692
}
693
*pfield_count = count;
694
*pfield = finfo;
695
return ret;
696
}
697
698