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 3807 2005-11-26 21:51:11Z edwin $
41 #include "mm/memory.h"
42 #include "vm/classcache.h"
43 #include "vm/exceptions.h"
44 #include "vm/stringlocal.h"
45 #include "vm/tables.h"
49 /* initial number of slots in the classcache hash table */
50 #define CLASSCACHE_INIT_SIZE 2048
52 /*============================================================================*/
54 /*============================================================================*/
56 /*#define CLASSCACHE_VERBOSE*/
59 #define CLASSCACHE_DEBUG
62 #ifdef CLASSCACHE_DEBUG
63 #define CLASSCACHE_ASSERT(cond) assert(cond)
65 #define CLASSCACHE_ASSERT(cond)
68 /*============================================================================*/
69 /* THREAD-SAFE LOCKING */
70 /*============================================================================*/
72 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
73 /* CAUTION: The static functions below are */
74 /* NOT synchronized! */
75 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
77 #if defined(USE_THREADS)
78 # define CLASSCACHE_LOCK() builtin_monitorenter(lock_classcache_hashtable)
79 # define CLASSCACHE_UNLOCK() builtin_monitorexit(lock_classcache_hashtable)
81 # define CLASSCACHE_LOCK()
82 # define CLASSCACHE_UNLOCK()
85 /*============================================================================*/
86 /* GLOBAL VARIABLES */
87 /*============================================================================*/
89 #if defined(USE_THREADS)
90 static java_objectheader *lock_classcache_hashtable;
93 hashtable classcache_hash;
95 /*============================================================================*/
97 /*============================================================================*/
99 /* classcache_init *************************************************************
101 Initialize the loaded class cache
103 Note: NOT synchronized!
105 *******************************************************************************/
107 bool classcache_init(void)
109 #if defined(USE_THREADS)
110 /* create utf hashtable lock object */
112 lock_classcache_hashtable = NEW(java_objectheader);
114 # if defined(NATIVE_THREADS)
115 initObjectLock(lock_classcache_hashtable);
119 init_hashtable(&classcache_hash, CLASSCACHE_INIT_SIZE);
121 /* everything's ok */
126 /* classcache_new_loader_entry *************************************************
128 Create a new classcache_loader_entry struct
129 (internally used helper function)
132 loader...........the ClassLoader object
133 next.............the next classcache_loader_entry
136 the new classcache_loader_entry
138 *******************************************************************************/
140 static classcache_loader_entry *
141 classcache_new_loader_entry(
142 /*@shared@*/ /*@null@*/ classloader * loader,
143 /*@only @*/ /*@null@*/ classcache_loader_entry * next)
145 classcache_loader_entry *lden;
147 lden = NEW(classcache_loader_entry);
148 lden->loader = loader;
154 /* classcache_merge_loaders ****************************************************
156 Merge two lists of loaders into one
157 (internally used helper function)
160 lista............first list (may be NULL)
161 listb............second list (may be NULL)
164 the merged list (may be NULL)
167 The lists given as arguments are destroyed!
169 *******************************************************************************/
171 static /*@null@*/ classcache_loader_entry *
172 classcache_merge_loaders(
173 /*@null@*/ classcache_loader_entry * lista,
174 /*@null@*/ classcache_loader_entry * listb)
176 classcache_loader_entry *result;
177 classcache_loader_entry *ldenA;
178 classcache_loader_entry *ldenB;
179 classcache_loader_entry **chain;
181 /* XXX This is a quadratic algorithm. If this ever
182 * becomes a problem, the loader lists should be
183 * stored as sorted lists and merged in linear time. */
188 for (ldenA = lista; ldenA != NULL; ldenA = ldenA->next) {
190 for (ldenB = listb; ldenB != NULL; ldenB = ldenB->next) {
191 if (ldenB->loader == ldenA->loader)
195 /* this loader is only in lista */
197 chain = &(ldenA->next);
200 /* XXX free the duplicated element */
204 /* concat listb to the result */
211 /* classcache_lookup_name ******************************************************
213 Lookup a name in the first level of the cache
214 (internally used helper function)
217 name.............the name to look up
220 a pointer to the classcache_name_entry for this name, or
221 null if no entry was found.
223 *******************************************************************************/
225 static classcache_name_entry *classcache_lookup_name(utf *name)
227 classcache_name_entry *c; /* hash table element */
228 u4 key; /* hashkey computed from classname */
229 u4 slot; /* slot in hashtable */
232 key = utf_hashkey(name->text, (u4) name->blength);
233 slot = key & (classcache_hash.size - 1);
234 c = classcache_hash.ptr[slot];
236 /* search external hash chain for the entry */
239 /* entry found in hashtable */
244 c = c->hashlink; /* next element in external chain */
253 /* classcache_new_name *********************************************************
255 Return a classcache_name_entry for the given name. The entry is created
256 if it is not already in the cache.
257 (internally used helper function)
260 name.............the name to look up / create an entry for
263 a pointer to the classcache_name_entry for this name
265 *******************************************************************************/
267 static classcache_name_entry *classcache_new_name(utf *name)
269 classcache_name_entry *c; /* hash table element */
270 u4 key; /* hashkey computed from classname */
271 u4 slot; /* slot in hashtable */
274 key = utf_hashkey(name->text, (u4) name->blength);
275 slot = key & (classcache_hash.size - 1);
276 c = classcache_hash.ptr[slot];
278 /* search external hash chain for the entry */
281 /* entry found in hashtable */
286 c = c->hashlink; /* next element in external chain */
289 /* location in hashtable found, create new entry */
291 c = NEW(classcache_name_entry);
296 /* insert entry into hashtable */
297 c->hashlink = (classcache_name_entry *) classcache_hash.ptr[slot];
298 classcache_hash.ptr[slot] = c;
300 /* update number of hashtable-entries */
301 classcache_hash.entries++;
303 if (classcache_hash.entries > (classcache_hash.size * 2)) {
305 /* reorganization of hashtable, average length of
306 the external chains is approx. 2 */
308 classcache_name_entry *c2;
309 hashtable newhash; /* the new hashtable */
311 /* create new hashtable, double the size */
313 init_hashtable(&newhash, classcache_hash.size * 2);
314 newhash.entries = classcache_hash.entries;
316 /* transfer elements to new hashtable */
318 for (i = 0; i < classcache_hash.size; i++) {
319 c2 = (classcache_name_entry *) classcache_hash.ptr[i];
321 classcache_name_entry *nextc = c2->hashlink;
323 (utf_hashkey(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
325 c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
326 newhash.ptr[newslot] = c2;
332 /* dispose old table */
334 MFREE(classcache_hash.ptr, void *, classcache_hash.size);
335 classcache_hash = newhash;
342 /* classcache_lookup ***********************************************************
344 Lookup a possibly loaded class
347 initloader.......initiating loader for resolving the class name
348 classname........class name to look up
351 The return value is a pointer to the cached class object,
352 or NULL, if the class is not in the cache.
354 Note: synchronized with global tablelock
356 *******************************************************************************/
358 classinfo *classcache_lookup(classloader *initloader, utf *classname)
360 classcache_name_entry *en;
361 classcache_class_entry *clsen;
362 classcache_loader_entry *lden;
363 classinfo *cls = NULL;
367 en = classcache_lookup_name(classname);
370 /* iterate over all class entries */
372 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
373 /* check if this entry has been loaded by initloader */
375 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
376 if (lden->loader == initloader) {
377 /* found the loaded class entry */
379 CLASSCACHE_ASSERT(clsen->classobj != NULL);
380 cls = clsen->classobj;
393 /* classcache_lookup_defined ***************************************************
395 Lookup a class with the given name and defining loader
398 defloader........defining loader
399 classname........class name
402 The return value is a pointer to the cached class object,
403 or NULL, if the class is not in the cache.
405 *******************************************************************************/
407 classinfo *classcache_lookup_defined(classloader *defloader, utf *classname)
409 classcache_name_entry *en;
410 classcache_class_entry *clsen;
411 classinfo *cls = NULL;
415 en = classcache_lookup_name(classname);
418 /* iterate over all class entries */
419 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
420 if (!clsen->classobj)
423 /* check if this entry has been defined by defloader */
424 if (clsen->classobj->classloader == defloader) {
425 cls = clsen->classobj;
437 /* classcache_store ************************************************************
439 Store a loaded class. If a class of the same name has already been stored
440 with the same initiating loader, then the given class CLS is freed (if
441 possible) and the previously stored class is returned.
444 initloader.......initiating loader used to load the class
445 (may be NULL indicating the bootstrap loader)
446 cls..............class object to cache
447 mayfree..........true if CLS may be freed in case another class is
451 cls..............everything ok, the class was stored in the cache,
452 other classinfo..another class with the same (initloader,name) has been
453 stored earlier. CLS has been freed and the earlier
454 stored class is returned.
455 NULL.............an exception has been thrown.
457 Note: synchronized with global tablelock
459 *******************************************************************************/
461 /*@shared@*/ /*@null@*/ classinfo *
463 /*@shared@*/ /*@null@*/ classloader * initloader,
464 /*@shared@*/ classinfo * cls,
467 classcache_name_entry *en;
468 classcache_class_entry *clsen;
469 classcache_loader_entry *lden;
470 #ifdef CLASSCACHE_VERBOSE
471 char logbuffer[1024];
474 CLASSCACHE_ASSERT(cls != NULL);
475 CLASSCACHE_ASSERT(cls->loaded != 0);
479 #ifdef CLASSCACHE_VERBOSE
480 sprintf(logbuffer,"classcache_store (%p,%d,", (void*)initloader,mayfree);
481 utf_strcat(logbuffer, cls->name);
482 strcat(logbuffer,")");
486 en = classcache_new_name(cls->name);
488 CLASSCACHE_ASSERT(en != NULL);
490 /* iterate over all class entries */
491 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
493 /* check if this entry has already been loaded by initloader */
494 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
495 if (lden->loader == initloader) {
496 /* A class with the same (initloader,name) pair has been stored already. */
497 /* We free the given class and return the earlier one. */
498 #ifdef CLASSCACHE_VERBOSE
499 dolog("replacing %p with earlier loaded class %p",cls,clsen->classobj);
501 CLASSCACHE_ASSERT(clsen->classobj != NULL);
504 cls = clsen->classobj;
509 /* check if initloader is constrained to this entry */
510 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
511 if (lden->loader == initloader) {
512 /* we have to use this entry */
513 /* check if is has already been resolved to another class */
514 if (clsen->classobj != NULL && clsen->classobj != cls) {
515 /* a loading constraint is violated */
516 *exceptionptr = exceptions_new_linkageerror(
517 "loading constraint violated: ",cls);
518 goto return_exception;
521 /* record initloader as initiating loader */
522 clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
524 /* record the loaded class object */
525 clsen->classobj = cls;
534 /* create a new class entry for this class object with */
535 /* initiating loader initloader */
537 clsen = NEW(classcache_class_entry);
538 clsen->classobj = cls;
539 clsen->loaders = classcache_new_loader_entry(initloader, NULL);
540 clsen->constraints = NULL;
542 clsen->next = en->classes;
551 return NULL; /* exception */
554 /* classcache_store_unique *****************************************************
556 Store a loaded class as loaded by the bootstrap loader. This is a wrapper
557 aroung classcache_store that throws an exception if a class with the same
558 name has already been loaded by the bootstrap loader.
560 This function is used to register a few special classes during startup.
561 It should not be used otherwise.
564 cls..............class object to cache
567 true.............everything ok, the class was stored.
568 false............an exception has been thrown.
570 Note: synchronized with global tablelock
572 *******************************************************************************/
575 classcache_store_unique(
576 /*@shared@*/ classinfo *cls)
578 /*@shared@*/ classinfo *result;
580 result = classcache_store(NULL,cls,false);
585 *exceptionptr = new_internalerror("class already stored in the class cache");
592 /* classcache_store_defined ****************************************************
594 Store a loaded class after it has been defined. If the class has already
595 been defined by the same defining loader in another thread, free the given
596 class and returned the one which has been defined earlier.
599 cls..............class object to store. classloader must be set
600 (classloader may be NULL, for bootloader)
603 cls..............everything ok, the class was stored the cache,
604 other classinfo..the class had already been defined, CLS was freed, the
605 class which was defined earlier is returned,
606 NULL.............an exception has been thrown.
608 *******************************************************************************/
610 /*@shared@*/ /*@null@*/ classinfo *
611 classcache_store_defined(/*@shared@*/ classinfo *cls)
613 classcache_name_entry *en;
614 classcache_class_entry *clsen;
615 #ifdef CLASSCACHE_VERBOSE
616 char logbuffer[1024];
619 CLASSCACHE_ASSERT(cls != NULL);
620 CLASSCACHE_ASSERT(cls->loaded != 0);
624 #ifdef CLASSCACHE_VERBOSE
625 sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
626 utf_strcat(logbuffer, cls->name);
627 strcat(logbuffer,")");
631 en = classcache_new_name(cls->name);
633 CLASSCACHE_ASSERT(en != NULL);
635 /* iterate over all class entries */
636 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
638 /* check if this class has been defined by the same classloader */
639 if (clsen->classobj != NULL && clsen->classobj->classloader == cls->classloader) {
640 /* we found an earlier definition, delete the newer one */
641 /* (if it is a different classinfo) */
642 if (clsen->classobj != cls) {
643 #ifdef CLASSCACHE_VERBOSE
644 dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
647 cls = clsen->classobj;
653 /* create a new class entry for this class object */
654 /* the list of initiating loaders is empty at this point */
656 clsen = NEW(classcache_class_entry);
657 clsen->classobj = cls;
658 clsen->loaders = NULL;
659 clsen->constraints = NULL;
661 clsen->next = en->classes;
669 /* classcache_find_loader ******************************************************
671 Find the class entry loaded by or constrained to a given loader
672 (internally used helper function)
675 entry............the classcache_name_entry
676 loader...........the loader to look for
679 the classcache_class_entry for the given loader, or
680 NULL if no entry was found
682 *******************************************************************************/
684 static /*@exposed@*/ /*@null@*/ classcache_class_entry *
685 classcache_find_loader(
686 classcache_name_entry * entry,
687 /*@shared@*/ /*@null@*/ classloader * loader)
689 classcache_class_entry *clsen;
690 classcache_loader_entry *lden;
692 CLASSCACHE_ASSERT(entry != NULL);
694 /* iterate over all class entries */
695 for (clsen = entry->classes; clsen != NULL; clsen = clsen->next) {
697 /* check if this entry has already been loaded by initloader */
698 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
699 if (lden->loader == loader)
700 return clsen; /* found */
703 /* check if loader is constrained to this entry */
704 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
705 if (lden->loader == loader)
706 return clsen; /* found */
714 /* classcache_free_class_entry *************************************************
716 Free the memory used by a class entry
719 clsen............the classcache_class_entry to free
721 *******************************************************************************/
724 classcache_free_class_entry(
725 classcache_class_entry * clsen)
727 classcache_loader_entry *lden;
728 classcache_loader_entry *next;
730 CLASSCACHE_ASSERT(clsen != NULL);
732 for (lden = clsen->loaders; lden != NULL; lden = next) {
734 FREE(lden, classcache_loader_entry);
736 for (lden = clsen->constraints; lden != NULL; lden = next) {
738 FREE(lden, classcache_loader_entry);
741 FREE(clsen, classcache_class_entry);
744 /* classcache_remove_class_entry ***********************************************
746 Remove a classcache_class_entry from the list of possible resolution of
748 (internally used helper function)
751 entry............the classcache_name_entry
752 clsen............the classcache_class_entry to remove
754 *******************************************************************************/
757 classcache_remove_class_entry(
758 classcache_name_entry * entry,
759 classcache_class_entry * clsen)
761 classcache_class_entry **chain;
763 CLASSCACHE_ASSERT(entry != NULL);
764 CLASSCACHE_ASSERT(clsen != NULL);
766 chain = &(entry->classes);
768 if (*chain == clsen) {
769 *chain = clsen->next;
770 classcache_free_class_entry(clsen);
773 chain = &((*chain)->next);
777 /* classcache_free_name_entry **************************************************
779 Free the memory used by a name entry
782 entry............the classcache_name_entry to free
784 *******************************************************************************/
787 classcache_free_name_entry(
788 classcache_name_entry * entry)
790 classcache_class_entry *clsen;
791 classcache_class_entry *next;
793 CLASSCACHE_ASSERT(entry != NULL);
795 for (clsen = entry->classes; clsen; clsen = next) {
797 classcache_free_class_entry(clsen);
800 FREE(entry, classcache_name_entry);
803 /* classcache_free *************************************************************
805 Free the memory used by the class cache
808 The class cache may not be used any more after this call, except
809 when it is reinitialized with classcache_init.
811 Note: NOT synchronized!
813 *******************************************************************************/
818 /*@globals killed classcache_hash@*/
821 classcache_name_entry *entry;
822 classcache_name_entry *next;
824 for (slot = 0; slot < classcache_hash.size; ++slot) {
825 for (entry = (classcache_name_entry *) classcache_hash.ptr[slot]; entry; entry = next) {
826 next = entry->hashlink;
827 classcache_free_name_entry(entry);
831 MFREE(classcache_hash.ptr, voidptr, classcache_hash.size);
832 classcache_hash.size = 0;
833 classcache_hash.entries = 0;
834 classcache_hash.ptr = NULL;
837 /* classcache_add_constraint ***************************************************
839 Add a loading constraint
842 a................first initiating loader
843 b................second initiating loader
844 classname........class name
847 true.............everything ok, the constraint has been added,
848 false............an exception has been thrown.
850 Note: synchronized with global tablelock
852 *******************************************************************************/
855 classcache_add_constraint(
856 /*@shared@*/ /*@null@*/ classloader * a,
857 /*@shared@*/ /*@null@*/ classloader * b,
858 /*@shared@*/ utf * classname)
860 classcache_name_entry *en;
861 classcache_class_entry *clsenA;
862 classcache_class_entry *clsenB;
864 CLASSCACHE_ASSERT(classname != NULL);
866 #ifdef CLASSCACHE_VERBOSE
867 fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
868 utf_fprint_classname(stderr, classname);
869 fprintf(stderr, ")\n");
872 /* a constraint with a == b is trivially satisfied */
878 en = classcache_new_name(classname);
880 CLASSCACHE_ASSERT(en != NULL);
882 /* find the entry loaded by / constrained to each loader */
883 clsenA = classcache_find_loader(en, a);
884 clsenB = classcache_find_loader(en, b);
886 if (clsenA != NULL && clsenB != NULL) {
887 /* { both loaders have corresponding entries } */
889 /* if the entries are the same, the constraint is already recorded */
890 if (clsenA == clsenB)
893 /* check if the entries can be merged */
894 if (clsenA->classobj != NULL && clsenB->classobj != NULL
895 && clsenA->classobj != clsenB->classobj) {
896 /* no, the constraint is violated */
897 *exceptionptr = exceptions_new_linkageerror(
898 "loading constraint violated: ",clsenA->classobj);
899 goto return_exception;
902 /* yes, merge the entries */
903 /* clsenB will be merged into clsenA */
904 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
905 clsenB->loaders = NULL;
907 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
908 clsenB->constraints);
909 clsenB->constraints = NULL;
911 if (!clsenA->classobj)
912 clsenA->classobj = clsenB->classobj;
914 /* remove clsenB from the list of class entries */
915 classcache_remove_class_entry(en, clsenB);
918 /* { at most one of the loaders has a corresponding entry } */
920 /* set clsenA to the single class entry we have */
925 /* { no loader has a corresponding entry } */
927 /* create a new class entry with the constraint (a,b,en->name) */
928 clsenA = NEW(classcache_class_entry);
929 clsenA->classobj = NULL;
930 clsenA->loaders = NULL;
931 clsenA->constraints = classcache_new_loader_entry(b, NULL);
932 clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
934 clsenA->next = en->classes;
935 en->classes = clsenA;
938 /* make b the loader that has no corresponding entry */
942 /* loader b must be added to entry clsenA */
943 clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
953 return false; /* exception */
956 /*============================================================================*/
958 /*============================================================================*/
960 /* classcache_debug_dump *******************************************************
962 Print the contents of the loaded class cache to a stream
965 file.............output stream
967 Note: synchronized with global tablelock
969 *******************************************************************************/
972 classcache_debug_dump(
973 /*@shared@*/ FILE * file)
975 classcache_name_entry *c;
976 classcache_class_entry *clsen;
977 classcache_loader_entry *lden;
982 fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
983 fprintf(file, "hash size : %d\n", (int) classcache_hash.size);
984 fprintf(file, "hash entries: %d\n", (int) classcache_hash.entries);
987 for (slot = 0; slot < classcache_hash.size; ++slot) {
988 c = (classcache_name_entry *) classcache_hash.ptr[slot];
990 for (; c != NULL; c = c->hashlink) {
991 utf_fprint_classname(file, c->name);
994 /* iterate over all class entries */
995 for (clsen = c->classes; clsen != NULL; clsen = clsen->next) {
996 if (clsen->classobj) {
997 fprintf(file, " loaded %p\n", (void *) clsen->classobj);
1000 fprintf(file, " unresolved\n");
1002 fprintf(file, " loaders:");
1003 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
1004 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1006 fprintf(file, "\n constraints:");
1007 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
1008 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1010 fprintf(file, "\n");
1014 fprintf(file, "\n==============================================================\n\n");
1016 CLASSCACHE_UNLOCK();
1020 * These are local overrides for various environment variables in Emacs.
1021 * Please do not remove this and leave it at the end of the file, where
1022 * Emacs will automagically detect them.
1023 * ---------------------------------------------------------------------
1026 * indent-tabs-mode: t
1030 * vim:noexpandtab:sw=4:ts=4: