1 /* src/vm/classcache.c - loaded class cache and loading constraints
3 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6 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., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Edwin Steiner
29 Changes: Christian Thalinger
31 $Id: classcache.c 3888 2005-12-05 22:08:45Z twisti $
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"
49 /* initial number of slots in the classcache hash table */
50 #define CLASSCACHE_INIT_SIZE 2048
52 /*============================================================================*/
54 /*============================================================================*/
56 /*#define CLASSCACHE_VERBOSE*/
58 /*============================================================================*/
59 /* THREAD-SAFE LOCKING */
60 /*============================================================================*/
62 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
63 /* CAUTION: The static functions below are */
64 /* NOT synchronized! */
65 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
67 #if defined(USE_THREADS)
68 # define CLASSCACHE_LOCK() builtin_monitorenter(lock_hashtable_classcache)
69 # define CLASSCACHE_UNLOCK() builtin_monitorexit(lock_hashtable_classcache)
71 # define CLASSCACHE_LOCK()
72 # define CLASSCACHE_UNLOCK()
75 /*============================================================================*/
76 /* GLOBAL VARIABLES */
77 /*============================================================================*/
79 hashtable hashtable_classcache;
81 #if defined(USE_THREADS)
82 static java_objectheader *lock_hashtable_classcache;
86 /*============================================================================*/
88 /*============================================================================*/
90 /* classcache_init *************************************************************
92 Initialize the loaded class cache
94 Note: NOT synchronized!
96 *******************************************************************************/
98 bool classcache_init(void)
100 /* create the hashtable */
102 hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE);
104 #if defined(USE_THREADS)
105 /* create utf hashtable lock object */
107 lock_hashtable_classcache = NEW(java_objectheader);
109 # if defined(NATIVE_THREADS)
110 initObjectLock(lock_hashtable_classcache);
114 /* everything's ok */
119 /* classcache_new_loader_entry *************************************************
121 Create a new classcache_loader_entry struct
122 (internally used helper function)
125 loader...........the ClassLoader object
126 next.............the next classcache_loader_entry
129 the new classcache_loader_entry
131 *******************************************************************************/
133 static classcache_loader_entry * classcache_new_loader_entry(
134 classloader * loader,
135 classcache_loader_entry * next)
137 classcache_loader_entry *lden;
139 lden = NEW(classcache_loader_entry);
140 lden->loader = loader;
146 /* classcache_merge_loaders ****************************************************
148 Merge two lists of loaders into one
149 (internally used helper function)
152 lista............first list (may be NULL)
153 listb............second list (may be NULL)
156 the merged list (may be NULL)
159 The lists given as arguments are destroyed!
161 *******************************************************************************/
163 static classcache_loader_entry * classcache_merge_loaders(
164 classcache_loader_entry * lista,
165 classcache_loader_entry * listb)
167 classcache_loader_entry *result;
168 classcache_loader_entry *ldenA;
169 classcache_loader_entry *ldenB;
170 classcache_loader_entry **chain;
172 /* XXX This is a quadratic algorithm. If this ever
173 * becomes a problem, the loader lists should be
174 * stored as sorted lists and merged in linear time. */
179 for (ldenA = lista; ldenA; ldenA = ldenA->next) {
181 for (ldenB = listb; ldenB; ldenB = ldenB->next) {
182 if (ldenB->loader == ldenA->loader)
186 /* this loader is only in lista */
188 chain = &(ldenA->next);
191 /* XXX free the duplicated element */
195 /* concat listb to the result */
202 /* classcache_lookup_name ******************************************************
204 Lookup a name in the first level of the cache
205 (internally used helper function)
208 name.............the name to look up
211 a pointer to the classcache_name_entry for this name, or
212 null if no entry was found.
214 *******************************************************************************/
216 static classcache_name_entry *classcache_lookup_name(utf *name)
218 classcache_name_entry *c; /* hash table element */
219 u4 key; /* hashkey computed from classname */
220 u4 slot; /* slot in hashtable */
223 key = utf_hashkey(name->text, (u4) name->blength);
224 slot = key & (hashtable_classcache.size - 1);
225 c = hashtable_classcache.ptr[slot];
227 /* search external hash chain for the entry */
230 /* entry found in hashtable */
235 c = c->hashlink; /* next element in external chain */
244 /* classcache_new_name *********************************************************
246 Return a classcache_name_entry for the given name. The entry is created
247 if it is not already in the cache.
248 (internally used helper function)
251 name.............the name to look up / create an entry for
254 a pointer to the classcache_name_entry for this name
256 *******************************************************************************/
258 static classcache_name_entry *classcache_new_name(utf *name)
260 classcache_name_entry *c; /* hash table element */
261 u4 key; /* hashkey computed from classname */
262 u4 slot; /* slot in hashtable */
265 key = utf_hashkey(name->text, (u4) name->blength);
266 slot = key & (hashtable_classcache.size - 1);
267 c = hashtable_classcache.ptr[slot];
269 /* search external hash chain for the entry */
272 /* entry found in hashtable */
277 c = c->hashlink; /* next element in external chain */
280 /* location in hashtable found, create new entry */
282 c = NEW(classcache_name_entry);
287 /* insert entry into hashtable */
288 c->hashlink = (classcache_name_entry *) hashtable_classcache.ptr[slot];
289 hashtable_classcache.ptr[slot] = c;
291 /* update number of hashtable-entries */
292 hashtable_classcache.entries++;
294 if (hashtable_classcache.entries > (hashtable_classcache.size * 2)) {
296 /* reorganization of hashtable, average length of
297 the external chains is approx. 2 */
299 classcache_name_entry *c2;
300 hashtable newhash; /* the new hashtable */
302 /* create new hashtable, double the size */
304 hashtable_create(&newhash, hashtable_classcache.size * 2);
305 newhash.entries = hashtable_classcache.entries;
307 /* transfer elements to new hashtable */
309 for (i = 0; i < hashtable_classcache.size; i++) {
310 c2 = (classcache_name_entry *) hashtable_classcache.ptr[i];
312 classcache_name_entry *nextc = c2->hashlink;
314 (utf_hashkey(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
316 c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
317 newhash.ptr[newslot] = c2;
323 /* dispose old table */
325 MFREE(hashtable_classcache.ptr, void *, hashtable_classcache.size);
326 hashtable_classcache = newhash;
333 /* classcache_lookup ***********************************************************
335 Lookup a possibly loaded class
338 initloader.......initiating loader for resolving the class name
339 classname........class name to look up
342 The return value is a pointer to the cached class object,
343 or NULL, if the class is not in the cache.
345 Note: synchronized with global tablelock
347 *******************************************************************************/
349 classinfo *classcache_lookup(classloader *initloader, utf *classname)
351 classcache_name_entry *en;
352 classcache_class_entry *clsen;
353 classcache_loader_entry *lden;
354 classinfo *cls = NULL;
358 en = classcache_lookup_name(classname);
361 /* iterate over all class entries */
363 for (clsen = en->classes; clsen; clsen = clsen->next) {
364 /* check if this entry has been loaded by initloader */
366 for (lden = clsen->loaders; lden; lden = lden->next) {
367 if (lden->loader == initloader) {
368 /* found the loaded class entry */
370 assert(clsen->classobj);
371 cls = clsen->classobj;
384 /* classcache_lookup_defined ***************************************************
386 Lookup a class with the given name and defining loader
389 defloader........defining loader
390 classname........class name
393 The return value is a pointer to the cached class object,
394 or NULL, if the class is not in the cache.
396 *******************************************************************************/
398 classinfo *classcache_lookup_defined(classloader *defloader, utf *classname)
400 classcache_name_entry *en;
401 classcache_class_entry *clsen;
402 classinfo *cls = NULL;
406 en = classcache_lookup_name(classname);
409 /* iterate over all class entries */
410 for (clsen = en->classes; clsen; clsen = clsen->next) {
411 if (!clsen->classobj)
414 /* check if this entry has been defined by defloader */
415 if (clsen->classobj->classloader == defloader) {
416 cls = clsen->classobj;
428 /* classcache_lookup_defined_or_initiated **************************************
430 Lookup a class that has been defined or initiated by the given loader
433 loader...........defining or initiating loader
434 classname........class name to look up
437 The return value is a pointer to the cached class object,
438 or NULL, if the class is not in the cache.
440 Note: synchronized with global tablelock
442 *******************************************************************************/
444 classinfo *classcache_lookup_defined_or_initiated(classloader *loader,
447 classcache_name_entry *en;
448 classcache_class_entry *clsen;
449 classcache_loader_entry *lden;
450 classinfo *cls = NULL;
454 en = classcache_lookup_name(classname);
457 /* iterate over all class entries */
459 for (clsen = en->classes; clsen; clsen = clsen->next) {
461 /* check if this entry has been defined by loader */
462 if (clsen->classobj && clsen->classobj->classloader == loader) {
463 cls = clsen->classobj;
467 /* check if this entry has been initiated by loader */
468 for (lden = clsen->loaders; lden; lden = lden->next) {
469 if (lden->loader == loader) {
470 /* found the loaded class entry */
472 assert(clsen->classobj);
473 cls = clsen->classobj;
486 /* classcache_store ************************************************************
488 Store a loaded class. If a class of the same name has already been stored
489 with the same initiating loader, then the given class CLS is freed (if
490 possible) and the previously stored class is returned.
493 initloader.......initiating loader used to load the class
494 (may be NULL indicating the bootstrap loader)
495 cls..............class object to cache
496 mayfree..........true if CLS may be freed in case another class is
500 cls..............everything ok, the class was stored in the cache,
501 other classinfo..another class with the same (initloader,name) has been
502 stored earlier. CLS has been freed and the earlier
503 stored class is returned.
504 NULL.............an exception has been thrown.
506 Note: synchronized with global tablelock
508 *******************************************************************************/
510 classinfo *classcache_store(classloader *initloader, classinfo *cls,
513 classcache_name_entry *en;
514 classcache_class_entry *clsen;
515 classcache_loader_entry *lden;
516 #ifdef CLASSCACHE_VERBOSE
517 char logbuffer[1024];
521 assert(cls->state & CLASS_LOADED);
525 #ifdef CLASSCACHE_VERBOSE
526 sprintf(logbuffer,"classcache_store (%p,%d,", (void*)initloader,mayfree);
527 utf_strcat(logbuffer, cls->name);
528 strcat(logbuffer,")");
532 en = classcache_new_name(cls->name);
536 /* iterate over all class entries */
537 for (clsen = en->classes; clsen; clsen = clsen->next) {
539 /* check if this entry has already been loaded by initloader */
540 for (lden = clsen->loaders; lden; lden = lden->next) {
541 if (lden->loader == initloader && clsen->classobj != cls) {
542 /* A class with the same (initloader,name) pair has been stored already. */
543 /* We free the given class and return the earlier one. */
544 #ifdef CLASSCACHE_VERBOSE
545 dolog("replacing %p with earlier loaded class %p",cls,clsen->classobj);
547 assert(clsen->classobj);
550 cls = clsen->classobj;
555 /* check if initloader is constrained to this entry */
556 for (lden = clsen->constraints; lden; lden = lden->next) {
557 if (lden->loader == initloader) {
558 /* we have to use this entry */
559 /* check if is has already been resolved to another class */
560 if (clsen->classobj && clsen->classobj != cls) {
561 /* a loading constraint is violated */
562 *exceptionptr = exceptions_new_linkageerror(
563 "loading constraint violated: ",cls);
564 goto return_exception;
567 /* record initloader as initiating loader */
568 clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
570 /* record the loaded class object */
571 clsen->classobj = cls;
580 /* create a new class entry for this class object with */
581 /* initiating loader initloader */
583 clsen = NEW(classcache_class_entry);
584 clsen->classobj = cls;
585 clsen->loaders = classcache_new_loader_entry(initloader, NULL);
586 clsen->constraints = NULL;
588 clsen->next = en->classes;
597 return NULL; /* exception */
600 /* classcache_store_unique *****************************************************
602 Store a loaded class as loaded by the bootstrap loader. This is a wrapper
603 aroung classcache_store that throws an exception if a class with the same
604 name has already been loaded by the bootstrap loader.
606 This function is used to register a few special classes during startup.
607 It should not be used otherwise.
610 cls..............class object to cache
613 true.............everything ok, the class was stored.
614 false............an exception has been thrown.
616 Note: synchronized with global tablelock
618 *******************************************************************************/
620 bool classcache_store_unique(classinfo *cls)
624 result = classcache_store(NULL,cls,false);
629 *exceptionptr = new_internalerror("class already stored in the class cache");
636 /* classcache_store_defined ****************************************************
638 Store a loaded class after it has been defined. If the class has already
639 been defined by the same defining loader in another thread, free the given
640 class and returned the one which has been defined earlier.
643 cls..............class object to store. classloader must be set
644 (classloader may be NULL, for bootloader)
647 cls..............everything ok, the class was stored the cache,
648 other classinfo..the class had already been defined, CLS was freed, the
649 class which was defined earlier is returned,
650 NULL.............an exception has been thrown.
652 *******************************************************************************/
654 classinfo *classcache_store_defined(classinfo *cls)
656 classcache_name_entry *en;
657 classcache_class_entry *clsen;
658 #ifdef CLASSCACHE_VERBOSE
659 char logbuffer[1024];
663 assert(cls->state & CLASS_LOADED);
667 #ifdef CLASSCACHE_VERBOSE
668 sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
669 utf_strcat(logbuffer, cls->name);
670 strcat(logbuffer,")");
674 en = classcache_new_name(cls->name);
678 /* iterate over all class entries */
679 for (clsen = en->classes; clsen; clsen = clsen->next) {
681 /* check if this class has been defined by the same classloader */
682 if (clsen->classobj && clsen->classobj->classloader == cls->classloader) {
683 /* we found an earlier definition, delete the newer one */
684 /* (if it is a different classinfo) */
685 if (clsen->classobj != cls) {
686 #ifdef CLASSCACHE_VERBOSE
687 dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
690 cls = clsen->classobj;
696 /* create a new class entry for this class object */
697 /* the list of initiating loaders is empty at this point */
699 clsen = NEW(classcache_class_entry);
700 clsen->classobj = cls;
701 clsen->loaders = NULL;
702 clsen->constraints = NULL;
704 clsen->next = en->classes;
712 /* classcache_find_loader ******************************************************
714 Find the class entry loaded by or constrained to a given loader
715 (internally used helper function)
718 entry............the classcache_name_entry
719 loader...........the loader to look for
722 the classcache_class_entry for the given loader, or
723 NULL if no entry was found
725 *******************************************************************************/
727 static classcache_class_entry * classcache_find_loader(
728 classcache_name_entry * entry,
729 classloader * loader)
731 classcache_class_entry *clsen;
732 classcache_loader_entry *lden;
736 /* iterate over all class entries */
737 for (clsen = entry->classes; clsen; clsen = clsen->next) {
739 /* check if this entry has already been loaded by initloader */
740 for (lden = clsen->loaders; lden; lden = lden->next) {
741 if (lden->loader == loader)
742 return clsen; /* found */
745 /* check if loader is constrained to this entry */
746 for (lden = clsen->constraints; lden; lden = lden->next) {
747 if (lden->loader == loader)
748 return clsen; /* found */
756 /* classcache_free_class_entry *************************************************
758 Free the memory used by a class entry
761 clsen............the classcache_class_entry to free
763 *******************************************************************************/
765 static void classcache_free_class_entry(classcache_class_entry * clsen)
767 classcache_loader_entry *lden;
768 classcache_loader_entry *next;
772 for (lden = clsen->loaders; lden; lden = next) {
774 FREE(lden, classcache_loader_entry);
776 for (lden = clsen->constraints; lden; lden = next) {
778 FREE(lden, classcache_loader_entry);
781 FREE(clsen, classcache_class_entry);
784 /* classcache_remove_class_entry ***********************************************
786 Remove a classcache_class_entry from the list of possible resolution of
788 (internally used helper function)
791 entry............the classcache_name_entry
792 clsen............the classcache_class_entry to remove
794 *******************************************************************************/
796 static void classcache_remove_class_entry(classcache_name_entry * entry,
797 classcache_class_entry * clsen)
799 classcache_class_entry **chain;
804 chain = &(entry->classes);
806 if (*chain == clsen) {
807 *chain = clsen->next;
808 classcache_free_class_entry(clsen);
811 chain = &((*chain)->next);
815 /* classcache_free_name_entry **************************************************
817 Free the memory used by a name entry
820 entry............the classcache_name_entry to free
822 *******************************************************************************/
824 static void classcache_free_name_entry(classcache_name_entry * entry)
826 classcache_class_entry *clsen;
827 classcache_class_entry *next;
831 for (clsen = entry->classes; clsen; clsen = next) {
833 classcache_free_class_entry(clsen);
836 FREE(entry, classcache_name_entry);
839 /* classcache_free *************************************************************
841 Free the memory used by the class cache
844 The class cache may not be used any more after this call, except
845 when it is reinitialized with classcache_init.
847 Note: NOT synchronized!
849 *******************************************************************************/
851 void classcache_free(void)
854 classcache_name_entry *entry;
855 classcache_name_entry *next;
857 for (slot = 0; slot < hashtable_classcache.size; ++slot) {
858 for (entry = (classcache_name_entry *) hashtable_classcache.ptr[slot]; entry; entry = next) {
859 next = entry->hashlink;
860 classcache_free_name_entry(entry);
864 MFREE(hashtable_classcache.ptr, voidptr, hashtable_classcache.size);
865 hashtable_classcache.size = 0;
866 hashtable_classcache.entries = 0;
867 hashtable_classcache.ptr = NULL;
870 /* classcache_add_constraint ***************************************************
872 Add a loading constraint
875 a................first initiating loader
876 b................second initiating loader
877 classname........class name
880 true.............everything ok, the constraint has been added,
881 false............an exception has been thrown.
883 Note: synchronized with global tablelock
885 *******************************************************************************/
887 bool classcache_add_constraint(classloader * a,
891 classcache_name_entry *en;
892 classcache_class_entry *clsenA;
893 classcache_class_entry *clsenB;
897 #ifdef CLASSCACHE_VERBOSE
898 fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
899 utf_fprint_classname(stderr, classname);
900 fprintf(stderr, ")\n");
903 /* a constraint with a == b is trivially satisfied */
909 en = classcache_new_name(classname);
913 /* find the entry loaded by / constrained to each loader */
914 clsenA = classcache_find_loader(en, a);
915 clsenB = classcache_find_loader(en, b);
917 if (clsenA && clsenB) {
918 /* { both loaders have corresponding entries } */
920 /* if the entries are the same, the constraint is already recorded */
921 if (clsenA == clsenB)
924 /* check if the entries can be merged */
925 if (clsenA->classobj && clsenB->classobj
926 && clsenA->classobj != clsenB->classobj) {
927 /* no, the constraint is violated */
928 *exceptionptr = exceptions_new_linkageerror(
929 "loading constraint violated: ",clsenA->classobj);
930 goto return_exception;
933 /* yes, merge the entries */
934 /* clsenB will be merged into clsenA */
935 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
936 clsenB->loaders = NULL;
938 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
939 clsenB->constraints);
940 clsenB->constraints = NULL;
942 if (!clsenA->classobj)
943 clsenA->classobj = clsenB->classobj;
945 /* remove clsenB from the list of class entries */
946 classcache_remove_class_entry(en, clsenB);
949 /* { at most one of the loaders has a corresponding entry } */
951 /* set clsenA to the single class entry we have */
956 /* { no loader has a corresponding entry } */
958 /* create a new class entry with the constraint (a,b,en->name) */
959 clsenA = NEW(classcache_class_entry);
960 clsenA->classobj = NULL;
961 clsenA->loaders = NULL;
962 clsenA->constraints = classcache_new_loader_entry(b, NULL);
963 clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
965 clsenA->next = en->classes;
966 en->classes = clsenA;
969 /* make b the loader that has no corresponding entry */
973 /* loader b must be added to entry clsenA */
974 clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
984 return false; /* exception */
987 /*============================================================================*/
989 /*============================================================================*/
991 /* classcache_debug_dump *******************************************************
993 Print the contents of the loaded class cache to a stream
996 file.............output stream
998 Note: synchronized with global tablelock
1000 *******************************************************************************/
1003 void classcache_debug_dump(FILE * file)
1005 classcache_name_entry *c;
1006 classcache_class_entry *clsen;
1007 classcache_loader_entry *lden;
1012 fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
1013 fprintf(file, "hash size : %d\n", (int) hashtable_classcache.size);
1014 fprintf(file, "hash entries: %d\n", (int) hashtable_classcache.entries);
1015 fprintf(file, "\n");
1017 for (slot = 0; slot < hashtable_classcache.size; ++slot) {
1018 c = (classcache_name_entry *) hashtable_classcache.ptr[slot];
1020 for (; c; c = c->hashlink) {
1021 utf_fprint_classname(file, c->name);
1022 fprintf(file, "\n");
1024 /* iterate over all class entries */
1025 for (clsen = c->classes; clsen; clsen = clsen->next) {
1026 if (clsen->classobj) {
1027 fprintf(file, " loaded %p\n", (void *) clsen->classobj);
1030 fprintf(file, " unresolved\n");
1032 fprintf(file, " loaders:");
1033 for (lden = clsen->loaders; lden; lden = lden->next) {
1034 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1036 fprintf(file, "\n constraints:");
1037 for (lden = clsen->constraints; lden; lden = lden->next) {
1038 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1040 fprintf(file, "\n");
1044 fprintf(file, "\n==============================================================\n\n");
1046 CLASSCACHE_UNLOCK();
1051 * These are local overrides for various environment variables in Emacs.
1052 * Please do not remove this and leave it at the end of the file, where
1053 * Emacs will automagically detect them.
1054 * ---------------------------------------------------------------------
1057 * indent-tabs-mode: t
1061 * vim:noexpandtab:sw=4:ts=4: