|
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 (*env)->ThrowNew(env, newExcCls, "Illegal mnum"); |
|
533 |
|
534 return NULL; |
|
535 } |
|
536 method = info->method[mnum].method_id; |
|
537 if ( method == NULL ) { |
|
538 char * name; |
|
539 char * sig; |
|
540 jclass clazz; |
|
541 |
|
542 name = (char *)string_get(info->method[mnum].name_index); |
|
543 if (name==NULL) { |
|
544 jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); |
|
545 (*env)->ThrowNew(env, newExcCls, "Name not found"); |
|
546 |
|
547 return NULL; |
|
548 } |
|
549 sig = (char *)string_get(info->method[mnum].sig_index); |
|
550 HPROF_ASSERT(sig!=NULL); |
|
551 clazz = class_get_class(env, index); |
|
552 if ( clazz != NULL ) { |
|
553 method = getMethodID(env, clazz, name, sig); |
|
554 HPROF_ASSERT(method!=NULL); |
|
555 info = get_info(index); |
|
556 info->method[mnum].method_id = method; |
|
557 } |
|
558 } |
|
559 return method; |
|
560 } |
|
561 |
|
562 void |
|
563 class_set_inst_size(ClassIndex index, jint inst_size) |
|
564 { |
|
565 ClassInfo *info; |
|
566 |
|
567 info = get_info(index); |
|
568 info->inst_size = inst_size; |
|
569 } |
|
570 |
|
571 jint |
|
572 class_get_inst_size(ClassIndex index) |
|
573 { |
|
574 ClassInfo *info; |
|
575 |
|
576 info = get_info(index); |
|
577 return info->inst_size; |
|
578 } |
|
579 |
|
580 void |
|
581 class_set_object_index(ClassIndex index, ObjectIndex object_index) |
|
582 { |
|
583 ClassInfo *info; |
|
584 |
|
585 info = get_info(index); |
|
586 info->object_index = object_index; |
|
587 } |
|
588 |
|
589 ObjectIndex |
|
590 class_get_object_index(ClassIndex index) |
|
591 { |
|
592 ClassInfo *info; |
|
593 |
|
594 info = get_info(index); |
|
595 return info->object_index; |
|
596 } |
|
597 |
|
598 ClassIndex |
|
599 class_get_super(ClassIndex index) |
|
600 { |
|
601 ClassInfo *info; |
|
602 |
|
603 info = get_info(index); |
|
604 return info->super; |
|
605 } |
|
606 |
|
607 void |
|
608 class_set_super(ClassIndex index, ClassIndex super) |
|
609 { |
|
610 ClassInfo *info; |
|
611 |
|
612 info = get_info(index); |
|
613 info->super = super; |
|
614 } |
|
615 |
|
616 LoaderIndex |
|
617 class_get_loader(ClassIndex index) |
|
618 { |
|
619 ClassKey *pkey; |
|
620 |
|
621 pkey = get_pkey(index); |
|
622 HPROF_ASSERT(pkey->loader_index!=0); |
|
623 return pkey->loader_index; |
|
624 } |
|
625 |
|
626 /* Get ALL class fields (supers too), return 1 on error, 0 if ok */ |
|
627 jint |
|
628 class_get_all_fields(JNIEnv *env, ClassIndex index, |
|
629 jint *pfield_count, FieldInfo **pfield) |
|
630 { |
|
631 ClassInfo *info; |
|
632 FieldInfo *finfo; |
|
633 jint count; |
|
634 jint ret; |
|
635 |
|
636 count = 0; |
|
637 finfo = NULL; |
|
638 ret = 1; /* Default is to return an error condition */ |
|
639 |
|
640 info = get_info(index); |
|
641 if ( info != NULL ) { |
|
642 if ( info->field_count >= 0 ) { |
|
643 /* Get cache */ |
|
644 count = info->field_count; |
|
645 finfo = info->field; |
|
646 ret = 0; /* Return of cache data, no error */ |
|
647 } else { |
|
648 jclass klass; |
|
649 |
|
650 klass = info->classref; |
|
651 if ( klass == NULL || isSameObject(env, klass, NULL) ) { |
|
652 /* This is probably an error because this will cause the field |
|
653 * index values to be off, but I'm hesitant to generate a |
|
654 * fatal error here, so I will issue something and continue. |
|
655 * I should have been holding a global reference to all the |
|
656 * jclass, so I'm not sure how this could happen. |
|
657 * Issuing a FindClass() here is just asking for trouble |
|
658 * because if the class went away, we aren't even sure |
|
659 * what ClassLoader to use. |
|
660 */ |
|
661 HPROF_ERROR(JNI_FALSE, "Missing jclass when fields needed"); |
|
662 } else { |
|
663 jint status; |
|
664 |
|
665 status = getClassStatus(klass); |
|
666 if ( status & |
|
667 (JVMTI_CLASS_STATUS_PRIMITIVE|JVMTI_CLASS_STATUS_ARRAY) ) { |
|
668 /* Set cache */ |
|
669 info->field_count = count; |
|
670 info->field = finfo; |
|
671 ret = 0; /* Primitive or array ok */ |
|
672 } else if ( status & JVMTI_CLASS_STATUS_PREPARED ) { |
|
673 /* Call JVMTI to get them */ |
|
674 getAllClassFieldInfo(env, klass, &count, &finfo); |
|
675 /* Set cache */ |
|
676 info->field_count = count; |
|
677 info->field = finfo; |
|
678 ret = 0; |
|
679 } |
|
680 } |
|
681 } |
|
682 } |
|
683 *pfield_count = count; |
|
684 *pfield = finfo; |
|
685 return ret; |
|
686 } |