1 /* src/vm/classcache.c - loaded class cache and loading constraints
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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@cacaojvm.org
27 Authors: Edwin Steiner
29 Changes: Christian Thalinger
31 $Id: classcache.c 4391 2006-01-31 15:18:37Z edwin $
41 #include "mm/memory.h"
42 #include "vm/classcache.h"
43 #include "vm/exceptions.h"
44 #include "vm/hashtable.h"
45 #include "vm/stringlocal.h"
48 /*************************************************************************
52 The classcache has two functions:
54 1) caching the resolution of class references
55 2) storing and checking loading constraints
57 We will use the following terms in this description:
59 N a class name: a utf string
60 (N,L) a class reference with initiating loader L and class name N
61 C a class (object): the result of resolving a reference (N,L)
62 We will write resultion as
64 (N,L1,L2) a loading constraint indicating that (N,L1) and (N,L2) must
65 resolve to the same class C. So (N,L1,L2) means
68 The functions of the classcache require:
70 1) a mapping (N,L) |--> C for looking up prior resolution results.
71 2) storing the current set of loading constraints { (N,L1,L2) }
73 These functions can be rearranged like that:
75 a mapping N |--> (a mapping L |--> C or NULL,
76 a set of constraints {(L1,L2)})
78 Thus we can treat the mapping and constraints for each name N
79 separately. The implementation does this by keeping a hash table
80 mapping a name N to a `classcache_name_entry` which contains all
81 info with respect to N.
83 For a class name N we can define an equivalence relation ~N~ on
86 L1 ~N~ L2 <==> *(N,L1) = *(N,L2)
88 A loading constraint (N,L1,L2) implies L1 ~N~ L2.
90 Also, if two references (N,L1) and (N,L2) resolve to the same class C
91 we have L1 ~N~ L2 because class loaders are required to return
92 consistent resolutions for a name N [XXX].
94 A `classcache_name_entry` keeps a set of tuples { (Cx,IL,CL) },
96 Cx...is a class C or NULL
97 IL...is the set of initiating loaders
98 CL...is the set of constraint loaders
100 Such a tuple is called `classcache_class_entry` in the source code.
102 The following holds for each tuple (Cx,IL,CL):
104 . Cx is NULL if and only if IL = {}.
106 . If Cx is a class, IL is the set of loaders that have been
107 recorded as initiating loaders for Cx.
109 . (IL u CL) is a subset of an equivalence class of ~N~.
111 (This means that all loaders in IL and CL must resolve
112 the name N to the same class.)
114 The implementation stores sets of loaders as linked lists of
115 `classcache_loader_entry`s.
117 *************************************************************************/
120 /* initial number of slots in the classcache hash table */
121 #define CLASSCACHE_INIT_SIZE 2048
123 /*============================================================================*/
125 /*============================================================================*/
127 /*#define CLASSCACHE_VERBOSE*/
129 /*============================================================================*/
130 /* THREAD-SAFE LOCKING */
131 /*============================================================================*/
133 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
134 /* CAUTION: The static functions below are */
135 /* NOT synchronized! */
136 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
138 #if defined(USE_THREADS)
139 # define CLASSCACHE_LOCK() builtin_monitorenter(lock_hashtable_classcache)
140 # define CLASSCACHE_UNLOCK() builtin_monitorexit(lock_hashtable_classcache)
142 # define CLASSCACHE_LOCK()
143 # define CLASSCACHE_UNLOCK()
146 /*============================================================================*/
147 /* GLOBAL VARIABLES */
148 /*============================================================================*/
150 hashtable hashtable_classcache;
152 #if defined(USE_THREADS)
153 static java_objectheader *lock_hashtable_classcache;
157 /*============================================================================*/
159 /*============================================================================*/
161 /* classcache_init *************************************************************
163 Initialize the loaded class cache
165 Note: NOT synchronized!
167 *******************************************************************************/
169 bool classcache_init(void)
171 /* create the hashtable */
173 hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE);
175 #if defined(USE_THREADS)
176 /* create utf hashtable lock object */
178 lock_hashtable_classcache = NEW(java_objectheader);
180 # if defined(NATIVE_THREADS)
181 initObjectLock(lock_hashtable_classcache);
185 /* everything's ok */
190 /* classcache_new_loader_entry *************************************************
192 Create a new classcache_loader_entry struct
193 (internally used helper function)
196 loader...........the ClassLoader object
197 next.............the next classcache_loader_entry
200 the new classcache_loader_entry
202 *******************************************************************************/
204 static classcache_loader_entry * classcache_new_loader_entry(
205 classloader * loader,
206 classcache_loader_entry * next)
208 classcache_loader_entry *lden;
210 lden = NEW(classcache_loader_entry);
211 lden->loader = loader;
217 /* classcache_merge_loaders ****************************************************
219 Merge two lists of loaders into one
220 (internally used helper function)
223 lista............first list (may be NULL)
224 listb............second list (may be NULL)
227 the merged list (may be NULL)
230 The lists given as arguments are destroyed!
232 *******************************************************************************/
234 static classcache_loader_entry * classcache_merge_loaders(
235 classcache_loader_entry * lista,
236 classcache_loader_entry * listb)
238 classcache_loader_entry *result;
239 classcache_loader_entry *ldenA;
240 classcache_loader_entry *ldenB;
241 classcache_loader_entry **chain;
243 /* XXX This is a quadratic algorithm. If this ever
244 * becomes a problem, the loader lists should be
245 * stored as sorted lists and merged in linear time. */
250 for (ldenA = lista; ldenA; ldenA = ldenA->next) {
252 for (ldenB = listb; ldenB; ldenB = ldenB->next) {
253 if (ldenB->loader == ldenA->loader)
257 /* this loader is only in lista */
259 chain = &(ldenA->next);
262 /* XXX free the duplicated element */
266 /* concat listb to the result */
273 /* classcache_lookup_name ******************************************************
275 Lookup a name in the first level of the cache
276 (internally used helper function)
279 name.............the name to look up
282 a pointer to the classcache_name_entry for this name, or
283 null if no entry was found.
285 *******************************************************************************/
287 static classcache_name_entry *classcache_lookup_name(utf *name)
289 classcache_name_entry *c; /* hash table element */
290 u4 key; /* hashkey computed from classname */
291 u4 slot; /* slot in hashtable */
294 key = utf_hashkey(name->text, (u4) name->blength);
295 slot = key & (hashtable_classcache.size - 1);
296 c = hashtable_classcache.ptr[slot];
298 /* search external hash chain for the entry */
301 /* entry found in hashtable */
306 c = c->hashlink; /* next element in external chain */
315 /* classcache_new_name *********************************************************
317 Return a classcache_name_entry for the given name. The entry is created
318 if it is not already in the cache.
319 (internally used helper function)
322 name.............the name to look up / create an entry for
325 a pointer to the classcache_name_entry for this name
327 *******************************************************************************/
329 static classcache_name_entry *classcache_new_name(utf *name)
331 classcache_name_entry *c; /* hash table element */
332 u4 key; /* hashkey computed from classname */
333 u4 slot; /* slot in hashtable */
336 key = utf_hashkey(name->text, (u4) name->blength);
337 slot = key & (hashtable_classcache.size - 1);
338 c = hashtable_classcache.ptr[slot];
340 /* search external hash chain for the entry */
343 /* entry found in hashtable */
348 c = c->hashlink; /* next element in external chain */
351 /* location in hashtable found, create new entry */
353 c = NEW(classcache_name_entry);
358 /* insert entry into hashtable */
359 c->hashlink = (classcache_name_entry *) hashtable_classcache.ptr[slot];
360 hashtable_classcache.ptr[slot] = c;
362 /* update number of hashtable-entries */
363 hashtable_classcache.entries++;
365 if (hashtable_classcache.entries > (hashtable_classcache.size * 2)) {
367 /* reorganization of hashtable, average length of
368 the external chains is approx. 2 */
370 classcache_name_entry *c2;
371 hashtable newhash; /* the new hashtable */
373 /* create new hashtable, double the size */
375 hashtable_create(&newhash, hashtable_classcache.size * 2);
376 newhash.entries = hashtable_classcache.entries;
378 /* transfer elements to new hashtable */
380 for (i = 0; i < hashtable_classcache.size; i++) {
381 c2 = (classcache_name_entry *) hashtable_classcache.ptr[i];
383 classcache_name_entry *nextc = c2->hashlink;
385 (utf_hashkey(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
387 c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
388 newhash.ptr[newslot] = c2;
394 /* dispose old table */
396 MFREE(hashtable_classcache.ptr, void *, hashtable_classcache.size);
397 hashtable_classcache = newhash;
404 /* classcache_lookup ***********************************************************
406 Lookup a possibly loaded class
409 initloader.......initiating loader for resolving the class name
410 classname........class name to look up
413 The return value is a pointer to the cached class object,
414 or NULL, if the class is not in the cache.
416 Note: synchronized with global tablelock
418 *******************************************************************************/
420 classinfo *classcache_lookup(classloader *initloader, utf *classname)
422 classcache_name_entry *en;
423 classcache_class_entry *clsen;
424 classcache_loader_entry *lden;
425 classinfo *cls = NULL;
429 en = classcache_lookup_name(classname);
432 /* iterate over all class entries */
434 for (clsen = en->classes; clsen; clsen = clsen->next) {
435 /* check if this entry has been loaded by initloader */
437 for (lden = clsen->loaders; lden; lden = lden->next) {
438 if (lden->loader == initloader) {
439 /* found the loaded class entry */
441 assert(clsen->classobj);
442 cls = clsen->classobj;
455 /* classcache_lookup_defined ***************************************************
457 Lookup a class with the given name and defining loader
460 defloader........defining loader
461 classname........class name
464 The return value is a pointer to the cached class object,
465 or NULL, if the class is not in the cache.
467 *******************************************************************************/
469 classinfo *classcache_lookup_defined(classloader *defloader, utf *classname)
471 classcache_name_entry *en;
472 classcache_class_entry *clsen;
473 classinfo *cls = NULL;
477 en = classcache_lookup_name(classname);
480 /* iterate over all class entries */
481 for (clsen = en->classes; clsen; clsen = clsen->next) {
482 if (!clsen->classobj)
485 /* check if this entry has been defined by defloader */
486 if (clsen->classobj->classloader == defloader) {
487 cls = clsen->classobj;
499 /* classcache_lookup_defined_or_initiated **************************************
501 Lookup a class that has been defined or initiated by the given loader
504 loader...........defining or initiating loader
505 classname........class name to look up
508 The return value is a pointer to the cached class object,
509 or NULL, if the class is not in the cache.
511 Note: synchronized with global tablelock
513 *******************************************************************************/
515 classinfo *classcache_lookup_defined_or_initiated(classloader *loader,
518 classcache_name_entry *en;
519 classcache_class_entry *clsen;
520 classcache_loader_entry *lden;
521 classinfo *cls = NULL;
525 en = classcache_lookup_name(classname);
528 /* iterate over all class entries */
530 for (clsen = en->classes; clsen; clsen = clsen->next) {
532 /* check if this entry has been defined by loader */
533 if (clsen->classobj && clsen->classobj->classloader == loader) {
534 cls = clsen->classobj;
538 /* check if this entry has been initiated by loader */
539 for (lden = clsen->loaders; lden; lden = lden->next) {
540 if (lden->loader == loader) {
541 /* found the loaded class entry */
543 assert(clsen->classobj);
544 cls = clsen->classobj;
557 /* classcache_store ************************************************************
559 Store a loaded class. If a class of the same name has already been stored
560 with the same initiating loader, then the given class CLS is freed (if
561 possible) and the previously stored class is returned.
564 initloader.......initiating loader used to load the class
565 (may be NULL indicating the bootstrap loader)
566 cls..............class object to cache
567 mayfree..........true if CLS may be freed in case another class is
571 cls..............everything ok, the class was stored in the cache,
572 other classinfo..another class with the same (initloader,name) has been
573 stored earlier. CLS has been freed and the earlier
574 stored class is returned.
575 NULL.............an exception has been thrown.
577 Note: synchronized with global tablelock
579 *******************************************************************************/
581 classinfo *classcache_store(classloader *initloader, classinfo *cls,
584 classcache_name_entry *en;
585 classcache_class_entry *clsen;
586 classcache_loader_entry *lden;
587 #ifdef CLASSCACHE_VERBOSE
588 char logbuffer[1024];
592 assert(cls->state & CLASS_LOADED);
596 #ifdef CLASSCACHE_VERBOSE
597 sprintf(logbuffer,"classcache_store (%p,%d,", (void*)initloader,mayfree);
598 utf_strcat(logbuffer, cls->name);
599 strcat(logbuffer,")");
603 en = classcache_new_name(cls->name);
607 /* iterate over all class entries */
608 for (clsen = en->classes; clsen; clsen = clsen->next) {
610 /* check if this entry has already been loaded by initloader */
611 for (lden = clsen->loaders; lden; lden = lden->next) {
612 if (lden->loader == initloader && clsen->classobj != cls) {
613 /* A class with the same (initloader,name) pair has been stored already. */
614 /* We free the given class and return the earlier one. */
615 #ifdef CLASSCACHE_VERBOSE
616 dolog("replacing %p with earlier loaded class %p",cls,clsen->classobj);
618 assert(clsen->classobj);
621 cls = clsen->classobj;
626 /* check if initloader is constrained to this entry */
627 for (lden = clsen->constraints; lden; lden = lden->next) {
628 if (lden->loader == initloader) {
629 /* we have to use this entry */
630 /* check if is has already been resolved to another class */
631 if (clsen->classobj && clsen->classobj != cls) {
632 /* a loading constraint is violated */
633 *exceptionptr = exceptions_new_linkageerror(
634 "loading constraint violated: ",cls);
635 goto return_exception;
638 /* record initloader as initiating loader */
639 clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
641 /* record the loaded class object */
642 clsen->classobj = cls;
651 /* create a new class entry for this class object with */
652 /* initiating loader initloader */
654 clsen = NEW(classcache_class_entry);
655 clsen->classobj = cls;
656 clsen->loaders = classcache_new_loader_entry(initloader, NULL);
657 clsen->constraints = NULL;
659 clsen->next = en->classes;
668 return NULL; /* exception */
671 /* classcache_store_unique *****************************************************
673 Store a loaded class as loaded by the bootstrap loader. This is a wrapper
674 aroung classcache_store that throws an exception if a class with the same
675 name has already been loaded by the bootstrap loader.
677 This function is used to register a few special classes during startup.
678 It should not be used otherwise.
681 cls..............class object to cache
684 true.............everything ok, the class was stored.
685 false............an exception has been thrown.
687 Note: synchronized with global tablelock
689 *******************************************************************************/
691 bool classcache_store_unique(classinfo *cls)
695 result = classcache_store(NULL,cls,false);
700 *exceptionptr = new_internalerror("class already stored in the class cache");
707 /* classcache_store_defined ****************************************************
709 Store a loaded class after it has been defined. If the class has already
710 been defined by the same defining loader in another thread, free the given
711 class and returned the one which has been defined earlier.
714 cls..............class object to store. classloader must be set
715 (classloader may be NULL, for bootloader)
718 cls..............everything ok, the class was stored the cache,
719 other classinfo..the class had already been defined, CLS was freed, the
720 class which was defined earlier is returned,
721 NULL.............an exception has been thrown.
723 *******************************************************************************/
725 classinfo *classcache_store_defined(classinfo *cls)
727 classcache_name_entry *en;
728 classcache_class_entry *clsen;
729 #ifdef CLASSCACHE_VERBOSE
730 char logbuffer[1024];
734 assert(cls->state & CLASS_LOADED);
738 #ifdef CLASSCACHE_VERBOSE
739 sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
740 utf_strcat(logbuffer, cls->name);
741 strcat(logbuffer,")");
745 en = classcache_new_name(cls->name);
749 /* iterate over all class entries */
750 for (clsen = en->classes; clsen; clsen = clsen->next) {
752 /* check if this class has been defined by the same classloader */
753 if (clsen->classobj && clsen->classobj->classloader == cls->classloader) {
754 /* we found an earlier definition, delete the newer one */
755 /* (if it is a different classinfo) */
756 if (clsen->classobj != cls) {
757 #ifdef CLASSCACHE_VERBOSE
758 dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
761 cls = clsen->classobj;
767 /* create a new class entry for this class object */
768 /* the list of initiating loaders is empty at this point */
770 clsen = NEW(classcache_class_entry);
771 clsen->classobj = cls;
772 clsen->loaders = NULL;
773 clsen->constraints = NULL;
775 clsen->next = en->classes;
783 /* classcache_find_loader ******************************************************
785 Find the class entry loaded by or constrained to a given loader
786 (internally used helper function)
789 entry............the classcache_name_entry
790 loader...........the loader to look for
793 the classcache_class_entry for the given loader, or
794 NULL if no entry was found
796 *******************************************************************************/
798 static classcache_class_entry * classcache_find_loader(
799 classcache_name_entry * entry,
800 classloader * loader)
802 classcache_class_entry *clsen;
803 classcache_loader_entry *lden;
807 /* iterate over all class entries */
808 for (clsen = entry->classes; clsen; clsen = clsen->next) {
810 /* check if this entry has already been loaded by initloader */
811 for (lden = clsen->loaders; lden; lden = lden->next) {
812 if (lden->loader == loader)
813 return clsen; /* found */
816 /* check if loader is constrained to this entry */
817 for (lden = clsen->constraints; lden; lden = lden->next) {
818 if (lden->loader == loader)
819 return clsen; /* found */
827 /* classcache_free_class_entry *************************************************
829 Free the memory used by a class entry
832 clsen............the classcache_class_entry to free
834 *******************************************************************************/
836 static void classcache_free_class_entry(classcache_class_entry * clsen)
838 classcache_loader_entry *lden;
839 classcache_loader_entry *next;
843 for (lden = clsen->loaders; lden; lden = next) {
845 FREE(lden, classcache_loader_entry);
847 for (lden = clsen->constraints; lden; lden = next) {
849 FREE(lden, classcache_loader_entry);
852 FREE(clsen, classcache_class_entry);
855 /* classcache_remove_class_entry ***********************************************
857 Remove a classcache_class_entry from the list of possible resolution of
859 (internally used helper function)
862 entry............the classcache_name_entry
863 clsen............the classcache_class_entry to remove
865 *******************************************************************************/
867 static void classcache_remove_class_entry(classcache_name_entry * entry,
868 classcache_class_entry * clsen)
870 classcache_class_entry **chain;
875 chain = &(entry->classes);
877 if (*chain == clsen) {
878 *chain = clsen->next;
879 classcache_free_class_entry(clsen);
882 chain = &((*chain)->next);
886 /* classcache_free_name_entry **************************************************
888 Free the memory used by a name entry
891 entry............the classcache_name_entry to free
893 *******************************************************************************/
895 static void classcache_free_name_entry(classcache_name_entry * entry)
897 classcache_class_entry *clsen;
898 classcache_class_entry *next;
902 for (clsen = entry->classes; clsen; clsen = next) {
904 classcache_free_class_entry(clsen);
907 FREE(entry, classcache_name_entry);
910 /* classcache_free *************************************************************
912 Free the memory used by the class cache
915 The class cache may not be used any more after this call, except
916 when it is reinitialized with classcache_init.
918 Note: NOT synchronized!
920 *******************************************************************************/
922 void classcache_free(void)
925 classcache_name_entry *entry;
926 classcache_name_entry *next;
928 for (slot = 0; slot < hashtable_classcache.size; ++slot) {
929 for (entry = (classcache_name_entry *) hashtable_classcache.ptr[slot]; entry; entry = next) {
930 next = entry->hashlink;
931 classcache_free_name_entry(entry);
935 MFREE(hashtable_classcache.ptr, voidptr, hashtable_classcache.size);
936 hashtable_classcache.size = 0;
937 hashtable_classcache.entries = 0;
938 hashtable_classcache.ptr = NULL;
941 /* classcache_add_constraint ***************************************************
943 Add a loading constraint
946 a................first initiating loader
947 b................second initiating loader
948 classname........class name
951 true.............everything ok, the constraint has been added,
952 false............an exception has been thrown.
954 Note: synchronized with global tablelock
956 *******************************************************************************/
958 bool classcache_add_constraint(classloader * a,
962 classcache_name_entry *en;
963 classcache_class_entry *clsenA;
964 classcache_class_entry *clsenB;
968 #ifdef CLASSCACHE_VERBOSE
969 fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
970 utf_fprint_classname(stderr, classname);
971 fprintf(stderr, ")\n");
974 /* a constraint with a == b is trivially satisfied */
980 en = classcache_new_name(classname);
984 /* find the entry loaded by / constrained to each loader */
985 clsenA = classcache_find_loader(en, a);
986 clsenB = classcache_find_loader(en, b);
988 if (clsenA && clsenB) {
989 /* { both loaders have corresponding entries } */
991 /* if the entries are the same, the constraint is already recorded */
992 if (clsenA == clsenB)
995 /* check if the entries can be merged */
996 if (clsenA->classobj && clsenB->classobj
997 && clsenA->classobj != clsenB->classobj) {
998 /* no, the constraint is violated */
999 *exceptionptr = exceptions_new_linkageerror(
1000 "loading constraint violated: ",clsenA->classobj);
1001 goto return_exception;
1004 /* yes, merge the entries */
1005 /* clsenB will be merged into clsenA */
1006 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
1007 clsenB->loaders = NULL;
1009 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
1010 clsenB->constraints);
1011 clsenB->constraints = NULL;
1013 if (!clsenA->classobj)
1014 clsenA->classobj = clsenB->classobj;
1016 /* remove clsenB from the list of class entries */
1017 classcache_remove_class_entry(en, clsenB);
1020 /* { at most one of the loaders has a corresponding entry } */
1022 /* set clsenA to the single class entry we have */
1027 /* { no loader has a corresponding entry } */
1029 /* create a new class entry with the constraint (a,b,en->name) */
1030 clsenA = NEW(classcache_class_entry);
1031 clsenA->classobj = NULL;
1032 clsenA->loaders = NULL;
1033 clsenA->constraints = classcache_new_loader_entry(b, NULL);
1034 clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
1036 clsenA->next = en->classes;
1037 en->classes = clsenA;
1040 /* make b the loader that has no corresponding entry */
1044 /* loader b must be added to entry clsenA */
1045 clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
1050 CLASSCACHE_UNLOCK();
1054 CLASSCACHE_UNLOCK();
1055 return false; /* exception */
1058 /*============================================================================*/
1060 /*============================================================================*/
1062 /* classcache_debug_dump *******************************************************
1064 Print the contents of the loaded class cache to a stream
1067 file.............output stream
1069 Note: synchronized with global tablelock
1071 *******************************************************************************/
1074 void classcache_debug_dump(FILE * file)
1076 classcache_name_entry *c;
1077 classcache_class_entry *clsen;
1078 classcache_loader_entry *lden;
1083 fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
1084 fprintf(file, "hash size : %d\n", (int) hashtable_classcache.size);
1085 fprintf(file, "hash entries: %d\n", (int) hashtable_classcache.entries);
1086 fprintf(file, "\n");
1088 for (slot = 0; slot < hashtable_classcache.size; ++slot) {
1089 c = (classcache_name_entry *) hashtable_classcache.ptr[slot];
1091 for (; c; c = c->hashlink) {
1092 utf_fprint_classname(file, c->name);
1093 fprintf(file, "\n");
1095 /* iterate over all class entries */
1096 for (clsen = c->classes; clsen; clsen = clsen->next) {
1097 if (clsen->classobj) {
1098 fprintf(file, " loaded %p\n", (void *) clsen->classobj);
1101 fprintf(file, " unresolved\n");
1103 fprintf(file, " loaders:");
1104 for (lden = clsen->loaders; lden; lden = lden->next) {
1105 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1107 fprintf(file, "\n constraints:");
1108 for (lden = clsen->constraints; lden; lden = lden->next) {
1109 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1111 fprintf(file, "\n");
1115 fprintf(file, "\n==============================================================\n\n");
1117 CLASSCACHE_UNLOCK();
1122 * These are local overrides for various environment variables in Emacs.
1123 * Please do not remove this and leave it at the end of the file, where
1124 * Emacs will automagically detect them.
1125 * ---------------------------------------------------------------------
1128 * indent-tabs-mode: t
1132 * vim:noexpandtab:sw=4:ts=4: