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