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