Line data Source code
1 : /* src/vm/classcache.cpp - loaded class cache and loading constraints
2 :
3 : Copyright (C) 1996-2013
4 : CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 :
6 : This file is part of CACAO.
7 :
8 : This program is free software; you can redistribute it and/or
9 : modify it under the terms of the GNU General Public License as
10 : published by the Free Software Foundation; either version 2, or (at
11 : your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program; if not, write to the Free Software
20 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 : 02110-1301, USA.
22 :
23 : */
24 :
25 :
26 : #include "config.h"
27 :
28 : #include <assert.h>
29 :
30 : #include "vm/types.hpp"
31 :
32 : #include "mm/memory.hpp"
33 :
34 : #include "threads/lock.hpp"
35 : #include "threads/mutex.hpp"
36 :
37 : #include "toolbox/hashtable.hpp"
38 : #include "toolbox/logging.hpp"
39 : #include "toolbox/buffer.hpp"
40 :
41 : #include "vm/class.hpp"
42 : #include "vm/classcache.hpp"
43 : #include "vm/descriptor.hpp"
44 : #include "vm/exceptions.hpp"
45 : #include "vm/options.hpp"
46 : #include "vm/method.hpp"
47 : #include "vm/utf8.hpp"
48 :
49 : /*************************************************************************
50 :
51 : Class Cache
52 :
53 : The classcache has two functions:
54 :
55 : 1) caching the resolution of class references
56 : 2) storing and checking loading constraints
57 :
58 : We will use the following terms in this description:
59 :
60 : N a class name: a utf string
61 : (N,L) a class reference with initiating loader L and class name N
62 : C a class (object): the result of resolving a reference (N,L)
63 : We will write resultion as
64 : C = *(N,L)
65 : (N,L1,L2) a loading constraint indicating that (N,L1) and (N,L2) must
66 : resolve to the same class C. So (N,L1,L2) means
67 : *(N,L1) = *(N,L2)
68 :
69 : The functions of the classcache require:
70 :
71 : 1) a mapping (N,L) |--> C for looking up prior resolution results.
72 : 2) storing the current set of loading constraints { (N,L1,L2) }
73 :
74 : These functions can be rearranged like that:
75 :
76 : a mapping N |--> (a mapping L |--> C or NULL,
77 : a set of constraints {(L1,L2)})
78 :
79 : Thus we can treat the mapping and constraints for each name N
80 : separately. The implementation does this by keeping a hash table
81 : mapping a name N to a `classcache_name_entry` which contains all
82 : info with respect to N.
83 :
84 : For a class name N we can define an equivalence relation ~N~ on
85 : class loaders:
86 :
87 : L1 ~N~ L2 <==> *(N,L1) = *(N,L2)
88 :
89 : A loading constraint (N,L1,L2) implies L1 ~N~ L2.
90 :
91 : Also, if two references (N,L1) and (N,L2) resolve to the same class C
92 : we have L1 ~N~ L2 because class loaders are required to return
93 : consistent resolutions for a name N [XXX].
94 :
95 : A `classcache_name_entry` keeps a set of tuples { (Cx,IL,CL) },
96 : where
97 : Cx...is a class C or NULL
98 : IL...is the set of initiating loaders
99 : CL...is the set of constrained loaders
100 :
101 : Such a tuple is called `classcache_class_entry` in the source code.
102 :
103 : The following holds for each tuple (Cx,IL,CL):
104 :
105 : . (Cx is NULL) implies IL = {}.
106 :
107 : . If Cx is a class, IL is the set of loaders that have been
108 : recorded as initiating loaders for Cx. IL may be the
109 : empty set {} in case Cx has already been defined but no
110 : initiating loader has been recorded, yet.
111 :
112 : . (IL u CL) is a subset of an equivalence class of ~N~.
113 :
114 : (This means that all loaders in IL and CL must resolve
115 : the name N to the same class.)
116 :
117 : The following holds for the set of tuples { (Cx,IL,CL) }:
118 :
119 : . For a given class C there is at most one tuple with Cx = C
120 : in the set. (There may be an arbitrary number of tuples
121 : with Cx = NULL, however.)
122 :
123 : . For a given loader L there is at most one tuple with
124 : L in (IL u CL).
125 :
126 : The implementation stores sets of loaders as linked lists of
127 : `classcache_loader_entry`s.
128 :
129 : Comments about manipulating the classcache can be found in the
130 : individual functions below.
131 :
132 : *************************************************************************/
133 :
134 :
135 : /* initial number of slots in the classcache hash table */
136 : #define CLASSCACHE_INIT_SIZE 2048
137 :
138 : /*============================================================================*/
139 : /* DEBUG HELPERS */
140 : /*============================================================================*/
141 :
142 : /* #define CLASSCACHE_VERBOSE */
143 :
144 : /*============================================================================*/
145 : /* STATISTICS */
146 : /*============================================================================*/
147 :
148 : /*#define CLASSCACHE_STATS*/
149 :
150 : #ifdef CLASSCACHE_STATS
151 : static int stat_classnames_stored = 0;
152 : static int stat_classes_stored = 0;
153 : static int stat_trivial_constraints = 0;
154 : static int stat_nontriv_constraints = 0;
155 : static int stat_nontriv_constraints_both = 0;
156 : static int stat_nontriv_constraints_merged = 0;
157 : static int stat_nontriv_constraints_one = 0;
158 : static int stat_nontriv_constraints_none = 0;
159 : static int stat_new_loader_entry = 0;
160 : static int stat_merge_class_entries = 0;
161 : static int stat_merge_loader_entries = 0;
162 : static int stat_lookup = 0;
163 : static int stat_lookup_class_entry_checked = 0;
164 : static int stat_lookup_loader_checked = 0;
165 : static int stat_lookup_name = 0;
166 : static int stat_lookup_name_entry = 0;
167 : static int stat_lookup_name_notfound = 0;
168 : static int stat_lookup_new_name = 0;
169 : static int stat_lookup_new_name_entry = 0;
170 : static int stat_lookup_new_name_collisions = 0;
171 : static int stat_rehash_names = 0;
172 : static int stat_rehash_names_collisions = 0;
173 :
174 : #define CLASSCACHE_COUNT(cnt) (cnt)++
175 : #define CLASSCACHE_COUNTIF(cond,cnt) do{if(cond) (cnt)++;} while(0)
176 :
177 : void classcache_print_statistics(FILE *file) {
178 : fprintf(file,"classnames stored : %8d\n",stat_classnames_stored);
179 : fprintf(file,"classes stored : %8d\n",stat_classes_stored);
180 : fprintf(file,"trivial constraints : %8d\n",stat_trivial_constraints);
181 : fprintf(file,"non-triv constraints: %8d\n",stat_nontriv_constraints);
182 : fprintf(file," both loaders rec.: %8d\n",stat_nontriv_constraints_both);
183 : fprintf(file," merged : %8d\n",stat_nontriv_constraints_merged);
184 : fprintf(file," one loader rec. : %8d\n",stat_nontriv_constraints_one);
185 : fprintf(file," no loaders rec. : %8d\n",stat_nontriv_constraints_none);
186 : fprintf(file,"new loader entries : %8d\n",stat_new_loader_entry);
187 : fprintf(file,"merge class entries : %8d\n",stat_merge_class_entries);
188 : fprintf(file,"merge loader entries: %8d\n",stat_merge_loader_entries);
189 : fprintf(file,"lookups : %8d\n",stat_lookup);
190 : fprintf(file," class entries ckd: %8d\n",stat_lookup_class_entry_checked);
191 : fprintf(file," loader checked : %8d\n",stat_lookup_loader_checked);
192 : fprintf(file,"lookup name : %8d\n",stat_lookup_name);
193 : fprintf(file," entries checked : %8d\n",stat_lookup_name_entry);
194 : fprintf(file," not found : %8d\n",stat_lookup_name_notfound);
195 : fprintf(file,"lookup (new) name : %8d\n",stat_lookup_new_name);
196 : fprintf(file," entries checked : %8d\n",stat_lookup_new_name_entry);
197 : fprintf(file," new collisions : %8d\n",stat_lookup_new_name_collisions);
198 : fprintf(file,"names rehashed : %8d times\n",stat_rehash_names);
199 : fprintf(file," collisions : %8d\n",stat_rehash_names_collisions);
200 : }
201 : #else
202 : #define CLASSCACHE_COUNT(cnt)
203 : #define CLASSCACHE_COUNTIF(cond,cnt)
204 : #endif
205 :
206 : /*============================================================================*/
207 : /* THREAD-SAFE LOCKING */
208 : /*============================================================================*/
209 :
210 : /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
211 : /* CAUTION: The static functions below are */
212 : /* NOT synchronized! */
213 : /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
214 :
215 : #define CLASSCACHE_LOCK() classcache_hashtable_mutex->lock();
216 : #define CLASSCACHE_UNLOCK() classcache_hashtable_mutex->unlock();
217 :
218 :
219 : /*============================================================================*/
220 : /* GLOBAL VARIABLES */
221 : /*============================================================================*/
222 :
223 : hashtable hashtable_classcache;
224 :
225 : static Mutex *classcache_hashtable_mutex;
226 :
227 :
228 : /*============================================================================*/
229 : /* */
230 : /*============================================================================*/
231 :
232 : /* prototypes */
233 :
234 : static void classcache_free_class_entry(classcache_class_entry *clsen);
235 : static void classcache_remove_class_entry(classcache_name_entry *en,
236 : classcache_class_entry *clsen);
237 :
238 :
239 : /* classcache_init *************************************************************
240 :
241 : Initialize the class cache
242 :
243 : Note: NOT synchronized!
244 :
245 : *******************************************************************************/
246 :
247 163 : bool classcache_init(void)
248 : {
249 163 : TRACESUBSYSTEMINITIALIZATION("classcache_init");
250 :
251 : /* create the hashtable */
252 :
253 163 : hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE);
254 :
255 : /* create utf hashtable mutex */
256 :
257 163 : classcache_hashtable_mutex = new Mutex();
258 :
259 : /* everything's ok */
260 :
261 163 : return true;
262 : }
263 :
264 : /* classcache_new_loader_entry *************************************************
265 :
266 : Create a new classcache_loader_entry struct
267 : (internally used helper function)
268 :
269 : IN:
270 : loader...........the ClassLoader object
271 : next.............the next classcache_loader_entry
272 :
273 : RETURN VALUE:
274 : the new classcache_loader_entry
275 :
276 : *******************************************************************************/
277 :
278 42320 : static classcache_loader_entry * classcache_new_loader_entry(
279 : classloader_t * loader,
280 : classcache_loader_entry * next)
281 : {
282 : classcache_loader_entry *lden;
283 :
284 42320 : lden = NEW(classcache_loader_entry);
285 42320 : lden->loader = loader;
286 42320 : lden->next = next;
287 : CLASSCACHE_COUNT(stat_new_loader_entry);
288 :
289 42320 : return lden;
290 : }
291 :
292 : /* classcache_merge_loaders ****************************************************
293 :
294 : Merge two lists of loaders into one
295 : (internally used helper function)
296 :
297 : IN:
298 : lista............first list (may be NULL)
299 : listb............second list (may be NULL)
300 :
301 : RETURN VALUE:
302 : the merged list (may be NULL)
303 :
304 : NOTE:
305 : The lists given as arguments are destroyed!
306 :
307 : *******************************************************************************/
308 :
309 2 : static classcache_loader_entry * classcache_merge_loaders(
310 : classcache_loader_entry * lista,
311 : classcache_loader_entry * listb)
312 : {
313 : classcache_loader_entry *result;
314 : classcache_loader_entry *ldenA;
315 : classcache_loader_entry *ldenB;
316 : classcache_loader_entry **chain;
317 :
318 : CLASSCACHE_COUNT(stat_merge_loader_entries);
319 :
320 : /* XXX This is a quadratic algorithm. If this ever
321 : * becomes a problem, the loader lists should be
322 : * stored as sorted lists and merged in linear time. */
323 :
324 2 : result = NULL;
325 2 : chain = &result;
326 :
327 5 : for (ldenA = lista; ldenA; ldenA = ldenA->next) {
328 :
329 4 : for (ldenB = listb; ldenB; ldenB = ldenB->next) {
330 1 : if (ldenB->loader == ldenA->loader)
331 0 : goto common_element;
332 : }
333 :
334 : /* this loader is only in lista */
335 3 : *chain = ldenA;
336 3 : chain = &(ldenA->next);
337 :
338 : common_element:
339 : /* XXX free the duplicated element */
340 : ;
341 : }
342 :
343 : /* concat listb to the result */
344 2 : *chain = listb;
345 :
346 2 : return result;
347 : }
348 :
349 : /* classcache_merge_class_entries **********************************************
350 :
351 : Merge two `classcache_class_entry`s into one.
352 : (internally used helper function)
353 :
354 : IN:
355 : en...............the classcache_name_entry containing both class entries
356 : clsenA...........first class entry, will receive the result
357 : clsenB...........second class entry
358 :
359 : PRE-CONDITION:
360 : Either both entries must have the same classobj, or one of them has
361 : classobj == NULL.
362 :
363 : NOTE:
364 : clsenB is freed by this function!
365 :
366 : *******************************************************************************/
367 :
368 1 : static void classcache_merge_class_entries(classcache_name_entry *en,
369 : classcache_class_entry *clsenA,
370 : classcache_class_entry *clsenB)
371 : {
372 : #ifdef CLASSCACHE_VERBOSE
373 : Buffer<> logbuffer;
374 : #endif
375 :
376 1 : assert(en);
377 1 : assert(clsenA);
378 1 : assert(clsenB);
379 1 : assert(!clsenA->classobj || !clsenB->classobj || clsenA->classobj == clsenB->classobj);
380 :
381 : #ifdef CLASSCACHE_VERBOSE
382 : logbuffer.writef("classcache_merge_class_entries(%p,%p->%p,%p->%p) ",
383 : (void*)en,(void*)clsenA,(void*)clsenA->classobj,(void*)clsenB,(void*)clsenB->classobj);
384 : if (clsenA->classobj)
385 : logbuffer.write_slash_to_dot(clsenA->classobj->name);
386 : if (clsenB->classobj)
387 : logbuffer.write_slash_to_dot(clsenB->classobj->name);
388 : log_println(logbuffer);
389 : #endif
390 :
391 : CLASSCACHE_COUNT(stat_merge_class_entries);
392 :
393 : /* clsenB will be merged into clsenA */
394 1 : clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
395 1 : clsenB->loaders = NULL; /* these have been freed or reused */
396 :
397 : clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
398 1 : clsenB->constraints);
399 1 : clsenB->constraints = NULL; /* these have been freed or reused */
400 :
401 1 : if (!clsenA->classobj)
402 1 : clsenA->classobj = clsenB->classobj;
403 :
404 : /* remove clsenB from the list of class entries */
405 1 : classcache_remove_class_entry(en, clsenB);
406 1 : }
407 :
408 :
409 : /* classcache_lookup_name ******************************************************
410 :
411 : Lookup a name in the first level of the cache
412 : (internally used helper function)
413 :
414 : IN:
415 : name.............the name to look up
416 :
417 : RETURN VALUE:
418 : a pointer to the classcache_name_entry for this name, or
419 : null if no entry was found.
420 :
421 : *******************************************************************************/
422 :
423 1307709 : static classcache_name_entry *classcache_lookup_name(Utf8String name)
424 : {
425 : classcache_name_entry *c; /* hash table element */
426 : u4 key; /* hashkey computed from classname */
427 : u4 slot; /* slot in hashtable */
428 :
429 : CLASSCACHE_COUNT(stat_lookup_name);
430 :
431 1307709 : key = name.hash();
432 1307709 : slot = key & (hashtable_classcache.size - 1);
433 1307709 : c = (classcache_name_entry*) hashtable_classcache.ptr[slot];
434 :
435 : /* search external hash chain for the entry */
436 :
437 2646917 : while (c) {
438 : /* entry found in hashtable */
439 : CLASSCACHE_COUNT(stat_lookup_name_entry);
440 :
441 1021110 : if (c->name == name)
442 989611 : return c;
443 :
444 31499 : c = c->hashlink; /* next element in external chain */
445 : }
446 :
447 : /* not found */
448 :
449 : CLASSCACHE_COUNT(stat_lookup_name_notfound);
450 318098 : return NULL;
451 : }
452 :
453 :
454 : /* classcache_new_name *********************************************************
455 :
456 : Return a classcache_name_entry for the given name. The entry is created
457 : if it is not already in the cache.
458 : (internally used helper function)
459 :
460 : IN:
461 : name.............the name to look up / create an entry for
462 :
463 : RETURN VALUE:
464 : a pointer to the classcache_name_entry for this name
465 :
466 : *******************************************************************************/
467 :
468 59865 : static classcache_name_entry *classcache_new_name(Utf8String name)
469 : {
470 : classcache_name_entry *c; /* hash table element */
471 : u4 key; /* hashkey computed from classname */
472 : u4 slot; /* slot in hashtable */
473 : u4 i;
474 :
475 : CLASSCACHE_COUNT(stat_lookup_new_name);
476 :
477 59865 : key = name.hash();
478 59865 : slot = key & (hashtable_classcache.size - 1);
479 59865 : c = (classcache_name_entry*) hashtable_classcache.ptr[slot];
480 :
481 : /* search external hash chain for the entry */
482 :
483 121985 : while (c) {
484 : /* entry found in hashtable */
485 : CLASSCACHE_COUNT(stat_lookup_new_name_entry);
486 :
487 20905 : if (c->name == name)
488 18650 : return c;
489 :
490 2255 : c = c->hashlink; /* next element in external chain */
491 : }
492 :
493 : /* location in hashtable found, create new entry */
494 :
495 41215 : c = NEW(classcache_name_entry);
496 :
497 41215 : c->name = name;
498 41215 : c->classes = NULL;
499 :
500 : /* insert entry into hashtable */
501 41215 : c->hashlink = (classcache_name_entry *) hashtable_classcache.ptr[slot];
502 : CLASSCACHE_COUNTIF(c->hashlink,stat_lookup_new_name_collisions);
503 41215 : hashtable_classcache.ptr[slot] = c;
504 :
505 : /* update number of hashtable-entries */
506 41215 : hashtable_classcache.entries++;
507 : CLASSCACHE_COUNT(stat_classnames_stored);
508 :
509 41215 : if ((hashtable_classcache.entries*2) > hashtable_classcache.size) {
510 : /* reorganization of hashtable */
511 :
512 : classcache_name_entry *c2;
513 : hashtable newhash; /* the new hashtable */
514 :
515 : CLASSCACHE_COUNT(stat_rehash_names);
516 :
517 : /* create new hashtable, double the size */
518 :
519 0 : hashtable_create(&newhash, hashtable_classcache.size * 2);
520 0 : newhash.entries = hashtable_classcache.entries;
521 :
522 : /* transfer elements to new hashtable */
523 :
524 0 : for (i = 0; i < hashtable_classcache.size; i++) {
525 0 : c2 = (classcache_name_entry *) hashtable_classcache.ptr[i];
526 0 : while (c2) {
527 0 : classcache_name_entry *nextc = c2->hashlink;
528 0 : u4 newslot = c2->name.hash() & (newhash.size - 1);
529 :
530 0 : c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
531 : CLASSCACHE_COUNTIF(c2->hashlink,stat_rehash_names_collisions);
532 0 : newhash.ptr[newslot] = c2;
533 :
534 0 : c2 = nextc;
535 : }
536 : }
537 :
538 : /* dispose old table */
539 :
540 0 : MFREE(hashtable_classcache.ptr, void *, hashtable_classcache.size);
541 0 : hashtable_classcache = newhash;
542 : }
543 :
544 41215 : return c;
545 : }
546 :
547 :
548 : /* classcache_lookup ***********************************************************
549 :
550 : Lookup a possibly loaded class
551 :
552 : IN:
553 : initloader.......initiating loader for resolving the class name
554 : classname........class name to look up
555 :
556 : RETURN VALUE:
557 : The return value is a pointer to the cached class object,
558 : or NULL, if the class is not in the cache.
559 :
560 : Note: synchronized with global tablelock
561 :
562 : *******************************************************************************/
563 :
564 1302151 : classinfo *classcache_lookup(classloader_t *initloader, Utf8String classname)
565 : {
566 : classcache_name_entry *en;
567 : classcache_class_entry *clsen;
568 : classcache_loader_entry *lden;
569 1302151 : classinfo *cls = NULL;
570 :
571 1302151 : CLASSCACHE_LOCK();
572 :
573 : CLASSCACHE_COUNT(stat_lookup);
574 1302151 : en = classcache_lookup_name(classname);
575 :
576 1302151 : if (en) {
577 : /* iterate over all class entries */
578 :
579 998923 : for (clsen = en->classes; clsen; clsen = clsen->next) {
580 : CLASSCACHE_COUNT(stat_lookup_class_entry_checked);
581 : /* check if this entry has been loaded by initloader */
582 :
583 1038567 : for (lden = clsen->loaders; lden; lden = lden->next) {
584 : CLASSCACHE_COUNT(stat_lookup_loader_checked);
585 1028515 : if (lden->loader == initloader) {
586 : /* found the loaded class entry */
587 :
588 978918 : assert(clsen->classobj);
589 978918 : cls = clsen->classobj;
590 978918 : goto found;
591 : }
592 : }
593 : }
594 : }
595 :
596 : found:
597 1302151 : CLASSCACHE_UNLOCK();
598 1302151 : return cls;
599 : }
600 :
601 :
602 : /* classcache_lookup_defined ***************************************************
603 :
604 : Lookup a class with the given name and defining loader
605 :
606 : IN:
607 : defloader........defining loader
608 : classname........class name
609 :
610 : RETURN VALUE:
611 : The return value is a pointer to the cached class object,
612 : or NULL, if the class is not in the cache.
613 :
614 : *******************************************************************************/
615 :
616 4916 : classinfo *classcache_lookup_defined(classloader_t *defloader, Utf8String classname)
617 : {
618 : classcache_name_entry *en;
619 : classcache_class_entry *clsen;
620 4916 : classinfo *cls = NULL;
621 :
622 4916 : CLASSCACHE_LOCK();
623 :
624 4916 : en = classcache_lookup_name(classname);
625 :
626 4916 : if (en) {
627 : /* iterate over all class entries */
628 1465 : for (clsen = en->classes; clsen; clsen = clsen->next) {
629 735 : if (!clsen->classobj)
630 6 : continue;
631 :
632 : /* check if this entry has been defined by defloader */
633 729 : if (clsen->classobj->classloader == defloader) {
634 3 : cls = clsen->classobj;
635 3 : goto found;
636 : }
637 : }
638 : }
639 :
640 : found:
641 4916 : CLASSCACHE_UNLOCK();
642 4916 : return cls;
643 : }
644 :
645 :
646 : /* classcache_lookup_defined_or_initiated **************************************
647 :
648 : Lookup a class that has been defined or initiated by the given loader
649 :
650 : IN:
651 : loader...........defining or initiating loader
652 : classname........class name to look up
653 :
654 : RETURN VALUE:
655 : The return value is a pointer to the cached class object,
656 : or NULL, if the class is not in the cache.
657 :
658 : Note: synchronized with global tablelock
659 :
660 : *******************************************************************************/
661 :
662 642 : classinfo *classcache_lookup_defined_or_initiated(classloader_t *loader,
663 : Utf8String classname)
664 : {
665 : classcache_name_entry *en;
666 : classcache_class_entry *clsen;
667 : classcache_loader_entry *lden;
668 642 : classinfo *cls = NULL;
669 :
670 642 : CLASSCACHE_LOCK();
671 :
672 642 : en = classcache_lookup_name(classname);
673 :
674 642 : if (en) {
675 : /* iterate over all class entries */
676 :
677 15 : for (clsen = en->classes; clsen; clsen = clsen->next) {
678 :
679 : /* check if this entry has been defined by loader */
680 8 : if (clsen->classobj && clsen->classobj->classloader == loader) {
681 0 : cls = clsen->classobj;
682 0 : goto found;
683 : }
684 :
685 : /* check if this entry has been initiated by loader */
686 15 : for (lden = clsen->loaders; lden; lden = lden->next) {
687 7 : if (lden->loader == loader) {
688 : /* found the loaded class entry */
689 :
690 0 : assert(clsen->classobj);
691 0 : cls = clsen->classobj;
692 0 : goto found;
693 : }
694 : }
695 : }
696 : }
697 :
698 : found:
699 642 : CLASSCACHE_UNLOCK();
700 642 : return cls;
701 : }
702 :
703 :
704 : /* classcache_store ************************************************************
705 :
706 : Store a loaded class. If a class of the same name has already been stored
707 : with the same initiating loader, then the given class CLS is freed (if
708 : possible) and the previously stored class is returned.
709 :
710 : IN:
711 : initloader.......initiating loader used to load the class
712 : (may be NULL indicating the bootstrap loader)
713 : cls..............class object to cache
714 : mayfree..........true if CLS may be freed in case another class is
715 : returned
716 :
717 : RETURN VALUE:
718 : cls..............everything ok, the class was stored in the cache,
719 : other classinfo..another class with the same (initloader,name) has been
720 : stored earlier. CLS has been freed[1] and the earlier
721 : stored class is returned.
722 : NULL.............an exception has been thrown.
723 :
724 : Note: synchronized with global tablelock
725 :
726 : [1]...in case MAYFREE is true
727 :
728 : *******************************************************************************/
729 :
730 43261 : classinfo *classcache_store(classloader_t *initloader, classinfo *cls,
731 : bool mayfree)
732 : {
733 : classcache_name_entry *en;
734 : classcache_class_entry *clsen;
735 : classcache_class_entry *clsenB;
736 : classcache_loader_entry *lden;
737 : #ifdef CLASSCACHE_VERBOSE
738 : Buffer<> logbuffer;
739 : #endif
740 :
741 43261 : assert(cls);
742 43261 : assert(cls->state & CLASS_LOADED);
743 :
744 43261 : CLASSCACHE_LOCK();
745 :
746 : #ifdef CLASSCACHE_VERBOSE
747 : logbuffer.writef("classcache_store (%p,%d,%p=", (void*)initloader,mayfree,(void*)cls)
748 : .write_slash_to_dot(cls->name)
749 : .write(")");
750 : log_println(logbuffer);
751 : #endif
752 :
753 43261 : en = classcache_new_name(cls->name);
754 :
755 43261 : assert(en);
756 :
757 : /* iterate over all class entries */
758 43885 : for (clsen = en->classes; clsen; clsen = clsen->next) {
759 :
760 : /* check if this entry has already been loaded by initloader */
761 2895 : for (lden = clsen->loaders; lden; lden = lden->next) {
762 2090 : if (lden->loader == initloader) {
763 1247 : if (clsen->classobj != cls) {
764 : /* A class with the same (initloader,name) pair has been stored already. */
765 : /* We free the given class and return the earlier one. */
766 : #ifdef CLASSCACHE_VERBOSE
767 : log_println("replacing %p with earlier loaded class %p",cls,clsen->classobj);
768 : #endif
769 0 : assert(clsen->classobj);
770 0 : if (mayfree)
771 0 : class_free(cls);
772 0 : cls = clsen->classobj;
773 : }
774 1247 : goto return_success;
775 : }
776 : }
777 :
778 : /* {This entry has not been resolved with initloader} */
779 :
780 : /* check if initloader is constrained to this entry */
781 812 : for (lden = clsen->constraints; lden; lden = lden->next) {
782 188 : if (lden->loader == initloader) {
783 : /* we have to use this entry. check if it has been resolved */
784 181 : if (clsen->classobj) {
785 : /* check if is has already been resolved to another class */
786 174 : if (clsen->classobj != cls) {
787 : /* a loading constraint is violated */
788 3 : exceptions_throw_linkageerror("loading constraint violated: ", cls);
789 3 : goto return_exception;
790 : }
791 :
792 : /* record initloader as initiating loader */
793 171 : clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
794 171 : goto return_success;
795 : }
796 :
797 : /* {this is the first resolution for this entry} */
798 : /* record initloader as initiating loader */
799 7 : clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
800 :
801 : /* maybe we can merge this entry with another one */
802 15 : for (clsenB = en->classes; clsenB; clsenB = clsenB->next) {
803 : /* we dont want the entry that we have already */
804 9 : if (clsenB->classobj == cls) {
805 : /* this entry has the same classobj. let's merge them */
806 1 : classcache_merge_class_entries(en,clsen,clsenB);
807 1 : goto return_success;
808 : }
809 : }
810 :
811 : /* record the loaded class object */
812 6 : clsen->classobj = cls;
813 : CLASSCACHE_COUNT(stat_classes_stored);
814 :
815 : /* done */
816 6 : goto return_success;
817 : }
818 : }
819 :
820 : }
821 :
822 : /* {There is no class entry containing initloader as initiating
823 : * or constrained loader.} */
824 :
825 : /* we look for a class entry with the same classobj we want to store */
826 41835 : for (clsen = en->classes; clsen; clsen = clsen->next) {
827 623 : if (clsen->classobj == cls) {
828 : /* this entry is about the same classobj. let's use it */
829 : /* check if this entry has already been loaded by initloader */
830 1274 : for (lden = clsen->loaders; lden; lden = lden->next) {
831 653 : if (lden->loader == initloader)
832 0 : goto return_success;
833 : }
834 621 : clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
835 621 : goto return_success;
836 : }
837 : }
838 :
839 : /* create a new class entry for this class object with */
840 : /* initiating loader initloader */
841 :
842 41212 : clsen = NEW(classcache_class_entry);
843 41212 : clsen->classobj = cls;
844 41212 : clsen->loaders = classcache_new_loader_entry(initloader, NULL);
845 41212 : clsen->constraints = NULL;
846 :
847 41212 : clsen->next = en->classes;
848 41212 : en->classes = clsen;
849 : CLASSCACHE_COUNT(stat_classes_stored);
850 :
851 : return_success:
852 : #ifdef CLASSCACHE_VERBOSE
853 : classcache_debug_dump(stdout,cls->name);
854 : #endif
855 43258 : CLASSCACHE_UNLOCK();
856 43258 : return cls;
857 :
858 : return_exception:
859 3 : CLASSCACHE_UNLOCK();
860 3 : return NULL; /* exception */
861 : }
862 :
863 : /* classcache_store_unique *****************************************************
864 :
865 : Store a loaded class as loaded by the bootstrap loader. This is a wrapper
866 : aroung classcache_store that throws an exception if a class with the same
867 : name has already been loaded by the bootstrap loader.
868 :
869 : This function is used to register a few special classes during startup.
870 : It should not be used otherwise.
871 :
872 : IN:
873 : cls..............class object to cache
874 :
875 : RETURN VALUE:
876 : true.............everything ok, the class was stored.
877 : false............an exception has been thrown.
878 :
879 : Note: synchronized with global tablelock
880 :
881 : *******************************************************************************/
882 :
883 489 : bool classcache_store_unique(classinfo *cls)
884 : {
885 : classinfo *result;
886 :
887 489 : result = classcache_store(NULL,cls,false);
888 489 : if (result == NULL)
889 0 : return false;
890 :
891 489 : if (result != cls) {
892 0 : exceptions_throw_internalerror("class already stored in the class cache");
893 0 : return false;
894 : }
895 :
896 489 : return true;
897 : }
898 :
899 : /* classcache_store_defined ****************************************************
900 :
901 : Store a loaded class after it has been defined. If the class has already
902 : been defined by the same defining loader in another thread, free the given
903 : class and returned the one which has been defined earlier.
904 :
905 : IN:
906 : cls..............class object to store. classloader must be set
907 : (classloader may be NULL, for bootloader)
908 :
909 : RETURN VALUE:
910 : cls..............everything ok, the class was stored the cache,
911 : other classinfo..the class had already been defined, CLS was freed, the
912 : class which was defined earlier is returned,
913 : NULL.............an exception has been thrown.
914 :
915 : *******************************************************************************/
916 :
917 0 : classinfo *classcache_store_defined(classinfo *cls)
918 : {
919 : classcache_name_entry *en;
920 : classcache_class_entry *clsen;
921 : #ifdef CLASSCACHE_VERBOSE
922 : Buffer<> logbuffer;
923 : #endif
924 :
925 0 : assert(cls);
926 0 : assert(cls->state & CLASS_LOADED);
927 :
928 0 : CLASSCACHE_LOCK();
929 :
930 : #ifdef CLASSCACHE_VERBOSE
931 : logbuffer.writef("classcache_store_defined (%p,", (void*)cls->classloader)
932 : .write_slash_to_dot(cls->name)
933 : .write(")");
934 : log_println(logbuffer);
935 : #endif
936 :
937 0 : en = classcache_new_name(cls->name);
938 :
939 0 : assert(en);
940 :
941 : /* iterate over all class entries */
942 0 : for (clsen = en->classes; clsen; clsen = clsen->next) {
943 :
944 : /* check if this class has been defined by the same classloader */
945 0 : if (clsen->classobj && clsen->classobj->classloader == cls->classloader) {
946 : /* we found an earlier definition, delete the newer one */
947 : /* (if it is a different classinfo) */
948 0 : if (clsen->classobj != cls) {
949 : #ifdef CLASSCACHE_VERBOSE
950 : log_println("replacing %p with earlier defined class %p",cls,clsen->classobj);
951 : #endif
952 0 : class_free(cls);
953 0 : cls = clsen->classobj;
954 : }
955 0 : goto return_success;
956 : }
957 : }
958 :
959 : /* create a new class entry for this class object */
960 : /* the list of initiating loaders is empty at this point */
961 :
962 0 : clsen = NEW(classcache_class_entry);
963 0 : clsen->classobj = cls;
964 0 : clsen->loaders = NULL;
965 0 : clsen->constraints = NULL;
966 :
967 0 : clsen->next = en->classes;
968 0 : en->classes = clsen;
969 : CLASSCACHE_COUNT(stat_classes_stored);
970 :
971 : return_success:
972 : #ifdef CLASSCACHE_VERBOSE
973 : classcache_debug_dump(stdout,cls->name);
974 : #endif
975 0 : CLASSCACHE_UNLOCK();
976 0 : return cls;
977 : }
978 :
979 : /* classcache_find_loader ******************************************************
980 :
981 : Find the class entry loaded by or constrained to a given loader
982 : (internally used helper function)
983 :
984 : IN:
985 : entry............the classcache_name_entry
986 : loader...........the loader to look for
987 :
988 : RETURN VALUE:
989 : the classcache_class_entry for the given loader, or
990 : NULL if no entry was found
991 :
992 : *******************************************************************************/
993 :
994 : #if defined(ENABLE_VERIFIER)
995 33208 : static classcache_class_entry * classcache_find_loader(
996 : classcache_name_entry * entry,
997 : classloader_t * loader)
998 : {
999 : classcache_class_entry *clsen;
1000 : classcache_loader_entry *lden;
1001 :
1002 33208 : assert(entry);
1003 :
1004 : /* iterate over all class entries */
1005 33559 : for (clsen = entry->classes; clsen; clsen = clsen->next) {
1006 :
1007 : /* check if this entry has already been loaded by initloader */
1008 50052 : for (lden = clsen->loaders; lden; lden = lden->next) {
1009 49329 : if (lden->loader == loader)
1010 32527 : return clsen; /* found */
1011 : }
1012 :
1013 : /* check if loader is constrained to this entry */
1014 835 : for (lden = clsen->constraints; lden; lden = lden->next) {
1015 484 : if (lden->loader == loader)
1016 372 : return clsen; /* found */
1017 : }
1018 : }
1019 :
1020 : /* not found */
1021 309 : return NULL;
1022 : }
1023 : #endif
1024 :
1025 : /* classcache_free_class_entry *************************************************
1026 :
1027 : Free the memory used by a class entry
1028 :
1029 : IN:
1030 : clsen............the classcache_class_entry to free
1031 :
1032 : *******************************************************************************/
1033 :
1034 1 : static void classcache_free_class_entry(classcache_class_entry * clsen)
1035 : {
1036 : classcache_loader_entry *lden;
1037 : classcache_loader_entry *next;
1038 :
1039 1 : assert(clsen);
1040 :
1041 1 : for (lden = clsen->loaders; lden; lden = next) {
1042 0 : next = lden->next;
1043 0 : FREE(lden, classcache_loader_entry);
1044 : }
1045 1 : for (lden = clsen->constraints; lden; lden = next) {
1046 0 : next = lden->next;
1047 0 : FREE(lden, classcache_loader_entry);
1048 : }
1049 :
1050 1 : FREE(clsen, classcache_class_entry);
1051 1 : }
1052 :
1053 : /* classcache_remove_class_entry ***********************************************
1054 :
1055 : Remove a classcache_class_entry from the list of possible resolution of
1056 : a name entry
1057 : (internally used helper function)
1058 :
1059 : IN:
1060 : entry............the classcache_name_entry
1061 : clsen............the classcache_class_entry to remove
1062 :
1063 : *******************************************************************************/
1064 :
1065 1 : static void classcache_remove_class_entry(classcache_name_entry * entry,
1066 : classcache_class_entry * clsen)
1067 : {
1068 : classcache_class_entry **chain;
1069 :
1070 1 : assert(entry);
1071 1 : assert(clsen);
1072 :
1073 1 : chain = &(entry->classes);
1074 3 : while (*chain) {
1075 2 : if (*chain == clsen) {
1076 1 : *chain = clsen->next;
1077 1 : classcache_free_class_entry(clsen);
1078 1 : return;
1079 : }
1080 1 : chain = &((*chain)->next);
1081 : }
1082 : }
1083 :
1084 : /* classcache_free_name_entry **************************************************
1085 :
1086 : Free the memory used by a name entry
1087 :
1088 : IN:
1089 : entry............the classcache_name_entry to free
1090 :
1091 : *******************************************************************************/
1092 :
1093 0 : static void classcache_free_name_entry(classcache_name_entry * entry)
1094 : {
1095 : classcache_class_entry *clsen;
1096 : classcache_class_entry *next;
1097 :
1098 0 : assert(entry);
1099 :
1100 0 : for (clsen = entry->classes; clsen; clsen = next) {
1101 0 : next = clsen->next;
1102 0 : classcache_free_class_entry(clsen);
1103 : }
1104 :
1105 0 : FREE(entry, classcache_name_entry);
1106 0 : }
1107 :
1108 : /* classcache_free *************************************************************
1109 :
1110 : Free the memory used by the class cache
1111 :
1112 : NOTE:
1113 : The class cache may not be used any more after this call, except
1114 : when it is reinitialized with classcache_init.
1115 :
1116 : Note: NOT synchronized!
1117 :
1118 : *******************************************************************************/
1119 :
1120 0 : void classcache_free(void)
1121 : {
1122 : u4 slot;
1123 : classcache_name_entry *entry;
1124 : classcache_name_entry *next;
1125 :
1126 0 : for (slot = 0; slot < hashtable_classcache.size; ++slot) {
1127 0 : for (entry = (classcache_name_entry *) hashtable_classcache.ptr[slot]; entry; entry = next) {
1128 0 : next = entry->hashlink;
1129 0 : classcache_free_name_entry(entry);
1130 : }
1131 : }
1132 :
1133 0 : MFREE(hashtable_classcache.ptr, void*, hashtable_classcache.size);
1134 0 : hashtable_classcache.size = 0;
1135 0 : hashtable_classcache.entries = 0;
1136 0 : hashtable_classcache.ptr = NULL;
1137 0 : }
1138 :
1139 : /* classcache_add_constraint ***************************************************
1140 :
1141 : Add a loading constraint
1142 :
1143 : IN:
1144 : a................first initiating loader
1145 : b................second initiating loader
1146 : classname........class name
1147 :
1148 : RETURN VALUE:
1149 : true.............everything ok, the constraint has been added,
1150 : false............an exception has been thrown.
1151 :
1152 : Note: synchronized with global tablelock
1153 :
1154 : *******************************************************************************/
1155 :
1156 : #if defined(ENABLE_VERIFIER)
1157 639053 : bool classcache_add_constraint(classloader_t * a,
1158 : classloader_t * b,
1159 : Utf8String classname)
1160 : {
1161 : classcache_name_entry *en;
1162 : classcache_class_entry *clsenA;
1163 : classcache_class_entry *clsenB;
1164 :
1165 639053 : assert(classname);
1166 :
1167 : #ifdef CLASSCACHE_VERBOSE
1168 : log_start();
1169 : log_print("classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
1170 : utf_fprint_printable_ascii_classname(stdout, classname);
1171 : log_print(")\n");
1172 : log_finish();
1173 : #endif
1174 :
1175 : /* a constraint with a == b is trivially satisfied */
1176 639053 : if (a == b) {
1177 : CLASSCACHE_COUNT(stat_trivial_constraints);
1178 622449 : return true;
1179 : }
1180 :
1181 16604 : CLASSCACHE_LOCK();
1182 :
1183 16604 : en = classcache_new_name(classname);
1184 :
1185 16604 : assert(en);
1186 : CLASSCACHE_COUNT(stat_nontriv_constraints);
1187 :
1188 : /* find the entry loaded by / constrained to each loader */
1189 16604 : clsenA = classcache_find_loader(en, a);
1190 16604 : clsenB = classcache_find_loader(en, b);
1191 :
1192 16604 : if (clsenA && clsenB) {
1193 : /* { both loaders have corresponding entries } */
1194 : CLASSCACHE_COUNT(stat_nontriv_constraints_both);
1195 :
1196 : /* if the entries are the same, the constraint is already recorded */
1197 16306 : if (clsenA == clsenB)
1198 16306 : goto return_success;
1199 :
1200 : /* check if the entries can be merged */
1201 0 : if (clsenA->classobj && clsenB->classobj
1202 : && clsenA->classobj != clsenB->classobj) {
1203 : /* no, the constraint is violated */
1204 : exceptions_throw_linkageerror("loading constraint violated: ",
1205 0 : clsenA->classobj);
1206 0 : goto return_exception;
1207 : }
1208 :
1209 : /* yes, merge the entries */
1210 0 : classcache_merge_class_entries(en,clsenA,clsenB);
1211 : CLASSCACHE_COUNT(stat_nontriv_constraints_merged);
1212 : }
1213 : else {
1214 : /* { at most one of the loaders has a corresponding entry } */
1215 :
1216 : /* set clsenA to the single class entry we have */
1217 298 : if (!clsenA)
1218 199 : clsenA = clsenB;
1219 :
1220 298 : if (!clsenA) {
1221 : /* { no loader has a corresponding entry } */
1222 : CLASSCACHE_COUNT(stat_nontriv_constraints_none);
1223 :
1224 : /* create a new class entry with the constraint (a,b,en->name) */
1225 11 : clsenA = NEW(classcache_class_entry);
1226 11 : clsenA->classobj = NULL;
1227 11 : clsenA->loaders = NULL;
1228 11 : clsenA->constraints = classcache_new_loader_entry(b, NULL);
1229 11 : clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
1230 :
1231 11 : clsenA->next = en->classes;
1232 11 : en->classes = clsenA;
1233 : }
1234 : else {
1235 : CLASSCACHE_COUNT(stat_nontriv_constraints_one);
1236 :
1237 : /* make b the loader that has no corresponding entry */
1238 287 : if (clsenB)
1239 188 : b = a;
1240 :
1241 : /* loader b must be added to entry clsenA */
1242 287 : clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
1243 : }
1244 : }
1245 :
1246 : return_success:
1247 16604 : CLASSCACHE_UNLOCK();
1248 16604 : return true;
1249 :
1250 : return_exception:
1251 0 : CLASSCACHE_UNLOCK();
1252 0 : return false; /* exception */
1253 : }
1254 : #endif /* defined(ENABLE_VERIFIER) */
1255 :
1256 : /* classcache_add_constraints_for_params ***************************************
1257 :
1258 : Add loading constraints for the parameters and return type of
1259 : the given method.
1260 :
1261 : IN:
1262 : a................first initiating loader
1263 : b................second initiating loader
1264 : m................methodinfo
1265 :
1266 : RETURN VALUE:
1267 : true.............everything ok, the constraints have been added,
1268 : false............an exception has been thrown.
1269 :
1270 : Note: synchronized with global tablelock
1271 :
1272 : *******************************************************************************/
1273 :
1274 : #if defined(ENABLE_VERIFIER)
1275 246251 : bool classcache_add_constraints_for_params(classloader_t * a,
1276 : classloader_t * b,
1277 : methodinfo *m)
1278 : {
1279 : methoddesc *md;
1280 : typedesc *td;
1281 : s4 i;
1282 :
1283 : /* a constraint with a == b is trivially satisfied */
1284 :
1285 246251 : if (a == b) {
1286 245945 : return true;
1287 : }
1288 :
1289 : /* get the parsed descriptor */
1290 :
1291 306 : assert(m);
1292 306 : md = m->parseddesc;
1293 306 : assert(md);
1294 :
1295 : /* constrain the return type */
1296 :
1297 306 : if (md->returntype.type == TYPE_ADR) {
1298 174 : if (!classcache_add_constraint(a, b, md->returntype.classref->name))
1299 0 : return false; /* exception */
1300 : }
1301 :
1302 : /* constrain each reference type used in the parameters */
1303 :
1304 306 : td = md->paramtypes;
1305 306 : i = md->paramcount;
1306 706 : for (; i--; td++) {
1307 400 : if (td->type != TYPE_ADR)
1308 0 : continue;
1309 :
1310 400 : if (!classcache_add_constraint(a, b, td->classref->name))
1311 0 : return false; /* exception */
1312 : }
1313 :
1314 : /* everything ok */
1315 306 : return true;
1316 : }
1317 : #endif /* defined(ENABLE_VERIFIER) */
1318 :
1319 :
1320 : /* classcache_number_of_loaded_classes *****************************************
1321 :
1322 : Counts the number of loaded classes and returns it.
1323 :
1324 : Note: This function assumes that the CLASSCACHE_LOCK is held by the
1325 : caller!
1326 :
1327 : *******************************************************************************/
1328 :
1329 0 : static s4 classcache_number_of_loaded_classes(void)
1330 : {
1331 : classcache_name_entry *en;
1332 : classcache_class_entry *clsen;
1333 : s4 number;
1334 : u4 i;
1335 :
1336 : /* initialize class counter */
1337 :
1338 0 : number = 0;
1339 :
1340 0 : for (i = 0; i < hashtable_classcache.size; i++) {
1341 : /* iterate over hashlink */
1342 :
1343 0 : for (en = (classcache_name_entry*) hashtable_classcache.ptr[i]; en != NULL; en = en->hashlink) {
1344 : /* filter pseudo classes $NEW$, $NULL$, $ARRAYSTUB$ out */
1345 :
1346 0 : if (en->name[0] == '$')
1347 0 : continue;
1348 :
1349 : /* iterate over classes with same name */
1350 :
1351 0 : for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
1352 : /* get only loaded classes */
1353 :
1354 0 : if (clsen->classobj != NULL)
1355 0 : number++;
1356 : }
1357 : }
1358 : }
1359 :
1360 0 : return number;
1361 : }
1362 :
1363 :
1364 : /* classcache_get_loaded_class_count *******************************************
1365 :
1366 : Counts the number of loaded classes and returns it.
1367 :
1368 : *******************************************************************************/
1369 :
1370 0 : s4 classcache_get_loaded_class_count(void)
1371 : {
1372 : s4 count;
1373 :
1374 0 : CLASSCACHE_LOCK();
1375 :
1376 0 : count = classcache_number_of_loaded_classes();
1377 :
1378 0 : CLASSCACHE_UNLOCK();
1379 :
1380 0 : return count;
1381 : }
1382 :
1383 :
1384 : /* classcache_foreach_loaded_class *********************************************
1385 :
1386 : Calls the given function for each loaded class.
1387 :
1388 : *******************************************************************************/
1389 :
1390 0 : void classcache_foreach_loaded_class(classcache_foreach_functionptr_t func,
1391 : void *data)
1392 : {
1393 : classcache_name_entry *en;
1394 : classcache_class_entry *clsen;
1395 : u4 i;
1396 :
1397 0 : CLASSCACHE_LOCK();
1398 :
1399 : /* look in every slot of the hashtable */
1400 :
1401 0 : for (i = 0; i < hashtable_classcache.size; i++) {
1402 : /* iterate over hashlink */
1403 :
1404 0 : for (en = (classcache_name_entry*) hashtable_classcache.ptr[i]; en != NULL; en = en->hashlink) {
1405 : /* filter pseudo classes $NEW$, $NULL$, $ARRAYSTUB$ out */
1406 :
1407 0 : if (en->name[0] == '$')
1408 0 : continue;
1409 :
1410 : /* iterate over classes with same name */
1411 :
1412 0 : for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
1413 : /* get only loaded classes */
1414 :
1415 0 : if (clsen->classobj != NULL) {
1416 0 : (*func)(clsen->classobj, data);
1417 : }
1418 : }
1419 : }
1420 : }
1421 :
1422 0 : CLASSCACHE_UNLOCK();
1423 0 : }
1424 :
1425 :
1426 : /*============================================================================*/
1427 : /* DEBUG DUMPS */
1428 : /*============================================================================*/
1429 :
1430 : /* classcache_debug_dump *******************************************************
1431 :
1432 : Print the contents of the loaded class cache to a stream
1433 :
1434 : IN:
1435 : file.............output stream
1436 : only.............if != NULL, only print entries for this name
1437 : (Currently we print also the rest of the hash chain to
1438 : get a feel for the average length of hash chains.)
1439 :
1440 : Note: synchronized with global tablelock
1441 :
1442 : *******************************************************************************/
1443 :
1444 : #ifndef NDEBUG
1445 0 : void classcache_debug_dump(FILE * file,Utf8String only)
1446 : {
1447 : classcache_name_entry *c;
1448 : classcache_class_entry *clsen;
1449 : classcache_loader_entry *lden;
1450 : u4 slot;
1451 :
1452 0 : CLASSCACHE_LOCK();
1453 :
1454 0 : log_println("=== [loaded class cache] =====================================");
1455 0 : log_println("hash size : %d", (int) hashtable_classcache.size);
1456 0 : log_println("hash entries: %d", (int) hashtable_classcache.entries);
1457 0 : log_println("");
1458 :
1459 0 : if (only) {
1460 0 : c = classcache_lookup_name(only);
1461 0 : slot = 0; /* avoid compiler warning */
1462 0 : goto dump_it;
1463 : }
1464 :
1465 0 : for (slot = 0; slot < hashtable_classcache.size; ++slot) {
1466 0 : c = (classcache_name_entry *) hashtable_classcache.ptr[slot];
1467 :
1468 : dump_it:
1469 0 : for (; c; c = c->hashlink) {
1470 0 : utf_fprint_printable_ascii_classname(file, c->name);
1471 0 : fprintf(file, "\n");
1472 :
1473 : /* iterate over all class entries */
1474 0 : for (clsen = c->classes; clsen; clsen = clsen->next) {
1475 0 : if (clsen->classobj) {
1476 0 : log_println(" loaded %p", (void *) clsen->classobj);
1477 : }
1478 : else {
1479 0 : log_println(" unresolved");
1480 : }
1481 :
1482 0 : log_start();
1483 0 : log_print(" loaders: ");
1484 0 : for (lden = clsen->loaders; lden; lden = lden->next) {
1485 0 : log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
1486 : }
1487 0 : log_finish();
1488 :
1489 0 : log_start();
1490 0 : log_print(" constraints: ");
1491 0 : for (lden = clsen->constraints; lden; lden = lden->next) {
1492 0 : log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
1493 : }
1494 0 : log_finish();
1495 : }
1496 : }
1497 :
1498 0 : if (only)
1499 0 : break;
1500 : }
1501 0 : fprintf(file, "\n==============================================================\n\n");
1502 :
1503 0 : CLASSCACHE_UNLOCK();
1504 0 : }
1505 :
1506 : #endif /* NDEBUG */
1507 :
1508 : /*
1509 : * These are local overrides for various environment variables in Emacs.
1510 : * Please do not remove this and leave it at the end of the file, where
1511 : * Emacs will automagically detect them.
1512 : * ---------------------------------------------------------------------
1513 : * Local variables:
1514 : * mode: c++
1515 : * indent-tabs-mode: t
1516 : * c-basic-offset: 4
1517 : * tab-width: 4
1518 : * End:
1519 : * vim:noexpandtab:sw=4:ts=4:
1520 : */
|