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