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 4486 2006-02-12 02:17:10Z 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) {
613 if (clsen->classobj != cls) {
614 /* A class with the same (initloader,name) pair has been stored already. */
615 /* We free the given class and return the earlier one. */
616 #ifdef CLASSCACHE_VERBOSE
617 dolog("replacing %p with earlier loaded class %p",cls,clsen->classobj);
619 assert(clsen->classobj);
622 cls = clsen->classobj;
628 /* check if initloader is constrained to this entry */
629 for (lden = clsen->constraints; lden; lden = lden->next) {
630 if (lden->loader == initloader) {
631 /* we have to use this entry */
632 /* check if is has already been resolved to another class */
633 if (clsen->classobj && clsen->classobj != cls) {
634 /* a loading constraint is violated */
635 *exceptionptr = exceptions_new_linkageerror(
636 "loading constraint violated: ",cls);
637 goto return_exception;
640 /* record initloader as initiating loader */
641 clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
643 /* record the loaded class object */
644 clsen->classobj = cls;
653 /* create a new class entry for this class object with */
654 /* initiating loader initloader */
656 clsen = NEW(classcache_class_entry);
657 clsen->classobj = cls;
658 clsen->loaders = classcache_new_loader_entry(initloader, NULL);
659 clsen->constraints = NULL;
661 clsen->next = en->classes;
670 return NULL; /* exception */
673 /* classcache_store_unique *****************************************************
675 Store a loaded class as loaded by the bootstrap loader. This is a wrapper
676 aroung classcache_store that throws an exception if a class with the same
677 name has already been loaded by the bootstrap loader.
679 This function is used to register a few special classes during startup.
680 It should not be used otherwise.
683 cls..............class object to cache
686 true.............everything ok, the class was stored.
687 false............an exception has been thrown.
689 Note: synchronized with global tablelock
691 *******************************************************************************/
693 bool classcache_store_unique(classinfo *cls)
697 result = classcache_store(NULL,cls,false);
702 *exceptionptr = new_internalerror("class already stored in the class cache");
709 /* classcache_store_defined ****************************************************
711 Store a loaded class after it has been defined. If the class has already
712 been defined by the same defining loader in another thread, free the given
713 class and returned the one which has been defined earlier.
716 cls..............class object to store. classloader must be set
717 (classloader may be NULL, for bootloader)
720 cls..............everything ok, the class was stored the cache,
721 other classinfo..the class had already been defined, CLS was freed, the
722 class which was defined earlier is returned,
723 NULL.............an exception has been thrown.
725 *******************************************************************************/
727 classinfo *classcache_store_defined(classinfo *cls)
729 classcache_name_entry *en;
730 classcache_class_entry *clsen;
731 #ifdef CLASSCACHE_VERBOSE
732 char logbuffer[1024];
736 assert(cls->state & CLASS_LOADED);
740 #ifdef CLASSCACHE_VERBOSE
741 sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
742 utf_strcat(logbuffer, cls->name);
743 strcat(logbuffer,")");
747 en = classcache_new_name(cls->name);
751 /* iterate over all class entries */
752 for (clsen = en->classes; clsen; clsen = clsen->next) {
754 /* check if this class has been defined by the same classloader */
755 if (clsen->classobj && clsen->classobj->classloader == cls->classloader) {
756 /* we found an earlier definition, delete the newer one */
757 /* (if it is a different classinfo) */
758 if (clsen->classobj != cls) {
759 #ifdef CLASSCACHE_VERBOSE
760 dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
763 cls = clsen->classobj;
769 /* create a new class entry for this class object */
770 /* the list of initiating loaders is empty at this point */
772 clsen = NEW(classcache_class_entry);
773 clsen->classobj = cls;
774 clsen->loaders = NULL;
775 clsen->constraints = NULL;
777 clsen->next = en->classes;
785 /* classcache_find_loader ******************************************************
787 Find the class entry loaded by or constrained to a given loader
788 (internally used helper function)
791 entry............the classcache_name_entry
792 loader...........the loader to look for
795 the classcache_class_entry for the given loader, or
796 NULL if no entry was found
798 *******************************************************************************/
800 static classcache_class_entry * classcache_find_loader(
801 classcache_name_entry * entry,
802 classloader * loader)
804 classcache_class_entry *clsen;
805 classcache_loader_entry *lden;
809 /* iterate over all class entries */
810 for (clsen = entry->classes; clsen; clsen = clsen->next) {
812 /* check if this entry has already been loaded by initloader */
813 for (lden = clsen->loaders; lden; lden = lden->next) {
814 if (lden->loader == loader)
815 return clsen; /* found */
818 /* check if loader is constrained to this entry */
819 for (lden = clsen->constraints; lden; lden = lden->next) {
820 if (lden->loader == loader)
821 return clsen; /* found */
829 /* classcache_free_class_entry *************************************************
831 Free the memory used by a class entry
834 clsen............the classcache_class_entry to free
836 *******************************************************************************/
838 static void classcache_free_class_entry(classcache_class_entry * clsen)
840 classcache_loader_entry *lden;
841 classcache_loader_entry *next;
845 for (lden = clsen->loaders; lden; lden = next) {
847 FREE(lden, classcache_loader_entry);
849 for (lden = clsen->constraints; lden; lden = next) {
851 FREE(lden, classcache_loader_entry);
854 FREE(clsen, classcache_class_entry);
857 /* classcache_remove_class_entry ***********************************************
859 Remove a classcache_class_entry from the list of possible resolution of
861 (internally used helper function)
864 entry............the classcache_name_entry
865 clsen............the classcache_class_entry to remove
867 *******************************************************************************/
869 static void classcache_remove_class_entry(classcache_name_entry * entry,
870 classcache_class_entry * clsen)
872 classcache_class_entry **chain;
877 chain = &(entry->classes);
879 if (*chain == clsen) {
880 *chain = clsen->next;
881 classcache_free_class_entry(clsen);
884 chain = &((*chain)->next);
888 /* classcache_free_name_entry **************************************************
890 Free the memory used by a name entry
893 entry............the classcache_name_entry to free
895 *******************************************************************************/
897 static void classcache_free_name_entry(classcache_name_entry * entry)
899 classcache_class_entry *clsen;
900 classcache_class_entry *next;
904 for (clsen = entry->classes; clsen; clsen = next) {
906 classcache_free_class_entry(clsen);
909 FREE(entry, classcache_name_entry);
912 /* classcache_free *************************************************************
914 Free the memory used by the class cache
917 The class cache may not be used any more after this call, except
918 when it is reinitialized with classcache_init.
920 Note: NOT synchronized!
922 *******************************************************************************/
924 void classcache_free(void)
927 classcache_name_entry *entry;
928 classcache_name_entry *next;
930 for (slot = 0; slot < hashtable_classcache.size; ++slot) {
931 for (entry = (classcache_name_entry *) hashtable_classcache.ptr[slot]; entry; entry = next) {
932 next = entry->hashlink;
933 classcache_free_name_entry(entry);
937 MFREE(hashtable_classcache.ptr, voidptr, hashtable_classcache.size);
938 hashtable_classcache.size = 0;
939 hashtable_classcache.entries = 0;
940 hashtable_classcache.ptr = NULL;
943 /* classcache_add_constraint ***************************************************
945 Add a loading constraint
948 a................first initiating loader
949 b................second initiating loader
950 classname........class name
953 true.............everything ok, the constraint has been added,
954 false............an exception has been thrown.
956 Note: synchronized with global tablelock
958 *******************************************************************************/
960 bool classcache_add_constraint(classloader * a,
964 classcache_name_entry *en;
965 classcache_class_entry *clsenA;
966 classcache_class_entry *clsenB;
970 #ifdef CLASSCACHE_VERBOSE
971 fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
972 utf_fprint_classname(stderr, classname);
973 fprintf(stderr, ")\n");
976 /* a constraint with a == b is trivially satisfied */
982 en = classcache_new_name(classname);
986 /* find the entry loaded by / constrained to each loader */
987 clsenA = classcache_find_loader(en, a);
988 clsenB = classcache_find_loader(en, b);
990 if (clsenA && clsenB) {
991 /* { both loaders have corresponding entries } */
993 /* if the entries are the same, the constraint is already recorded */
994 if (clsenA == clsenB)
997 /* check if the entries can be merged */
998 if (clsenA->classobj && clsenB->classobj
999 && clsenA->classobj != clsenB->classobj) {
1000 /* no, the constraint is violated */
1001 *exceptionptr = exceptions_new_linkageerror(
1002 "loading constraint violated: ",clsenA->classobj);
1003 goto return_exception;
1006 /* yes, merge the entries */
1007 /* clsenB will be merged into clsenA */
1008 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
1009 clsenB->loaders = NULL;
1011 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
1012 clsenB->constraints);
1013 clsenB->constraints = NULL;
1015 if (!clsenA->classobj)
1016 clsenA->classobj = clsenB->classobj;
1018 /* remove clsenB from the list of class entries */
1019 classcache_remove_class_entry(en, clsenB);
1022 /* { at most one of the loaders has a corresponding entry } */
1024 /* set clsenA to the single class entry we have */
1029 /* { no loader has a corresponding entry } */
1031 /* create a new class entry with the constraint (a,b,en->name) */
1032 clsenA = NEW(classcache_class_entry);
1033 clsenA->classobj = NULL;
1034 clsenA->loaders = NULL;
1035 clsenA->constraints = classcache_new_loader_entry(b, NULL);
1036 clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
1038 clsenA->next = en->classes;
1039 en->classes = clsenA;
1042 /* make b the loader that has no corresponding entry */
1046 /* loader b must be added to entry clsenA */
1047 clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
1052 CLASSCACHE_UNLOCK();
1056 CLASSCACHE_UNLOCK();
1057 return false; /* exception */
1060 /*============================================================================*/
1062 /*============================================================================*/
1064 /* classcache_debug_dump *******************************************************
1066 Print the contents of the loaded class cache to a stream
1069 file.............output stream
1071 Note: synchronized with global tablelock
1073 *******************************************************************************/
1076 void classcache_debug_dump(FILE * file)
1078 classcache_name_entry *c;
1079 classcache_class_entry *clsen;
1080 classcache_loader_entry *lden;
1085 fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
1086 fprintf(file, "hash size : %d\n", (int) hashtable_classcache.size);
1087 fprintf(file, "hash entries: %d\n", (int) hashtable_classcache.entries);
1088 fprintf(file, "\n");
1090 for (slot = 0; slot < hashtable_classcache.size; ++slot) {
1091 c = (classcache_name_entry *) hashtable_classcache.ptr[slot];
1093 for (; c; c = c->hashlink) {
1094 utf_fprint_classname(file, c->name);
1095 fprintf(file, "\n");
1097 /* iterate over all class entries */
1098 for (clsen = c->classes; clsen; clsen = clsen->next) {
1099 if (clsen->classobj) {
1100 fprintf(file, " loaded %p\n", (void *) clsen->classobj);
1103 fprintf(file, " unresolved\n");
1105 fprintf(file, " loaders:");
1106 for (lden = clsen->loaders; lden; lden = lden->next) {
1107 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1109 fprintf(file, "\n constraints:");
1110 for (lden = clsen->constraints; lden; lden = lden->next) {
1111 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1113 fprintf(file, "\n");
1117 fprintf(file, "\n==============================================================\n\n");
1119 CLASSCACHE_UNLOCK();
1124 * These are local overrides for various environment variables in Emacs.
1125 * Please do not remove this and leave it at the end of the file, where
1126 * Emacs will automagically detect them.
1127 * ---------------------------------------------------------------------
1130 * indent-tabs-mode: t
1134 * vim:noexpandtab:sw=4:ts=4: