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 3351 2005-10-05 11:53:28Z edwin $
38 #include "mm/memory.h"
39 #include "vm/classcache.h"
40 #include "vm/exceptions.h"
41 #include "vm/stringlocal.h"
42 #include "vm/tables.h"
46 /* initial number of slots in the classcache hash table */
47 #define CLASSCACHE_INIT_SIZE 2048
49 /*============================================================================*/
51 /*============================================================================*/
53 /*#define CLASSCACHE_VERBOSE*/
56 #define CLASSCACHE_DEBUG
59 #ifdef CLASSCACHE_DEBUG
60 #define CLASSCACHE_ASSERT(cond) assert(cond)
62 #define CLASSCACHE_ASSERT(cond)
65 /*============================================================================*/
66 /* THREAD-SAFE LOCKING */
67 /*============================================================================*/
69 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
70 /* CAUTION: The static functions below are */
71 /* NOT synchronized! */
72 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
74 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
75 # define CLASSCACHE_LOCK() tables_lock()
76 # define CLASSCACHE_UNLOCK() tables_unlock()
78 # define CLASSCACHE_LOCK()
79 # define CLASSCACHE_UNLOCK()
82 /*============================================================================*/
83 /* GLOBAL VARIABLES */
84 /*============================================================================*/
86 hashtable classcache_hash;
88 /*============================================================================*/
90 /*============================================================================*/
92 /* classcache_init *************************************************************
94 Initialize the loaded class cache
96 Note: NOT synchronized!
98 *******************************************************************************/
104 init_hashtable(&classcache_hash, CLASSCACHE_INIT_SIZE);
107 /* classcache_new_loader_entry *************************************************
109 Create a new classcache_loader_entry struct
110 (internally used helper function)
113 loader...........the ClassLoader object
114 next.............the next classcache_loader_entry
117 the new classcache_loader_entry
119 *******************************************************************************/
121 static classcache_loader_entry *
122 classcache_new_loader_entry(
123 /*@shared@*/ /*@null@*/ classloader * loader,
124 /*@only @*/ /*@null@*/ classcache_loader_entry * next)
126 classcache_loader_entry *lden;
128 lden = NEW(classcache_loader_entry);
129 lden->loader = loader;
135 /* classcache_merge_loaders ****************************************************
137 Merge two lists of loaders into one
138 (internally used helper function)
141 lista............first list (may be NULL)
142 listb............second list (may be NULL)
145 the merged list (may be NULL)
148 The lists given as arguments are destroyed!
150 *******************************************************************************/
152 static /*@null@*/ classcache_loader_entry *
153 classcache_merge_loaders(
154 /*@null@*/ classcache_loader_entry * lista,
155 /*@null@*/ classcache_loader_entry * listb)
157 classcache_loader_entry *result;
158 classcache_loader_entry *ldenA;
159 classcache_loader_entry *ldenB;
160 classcache_loader_entry **chain;
162 /* XXX This is a quadratic algorithm. If this ever
163 * becomes a problem, the loader lists should be
164 * stored as sorted lists and merged in linear time. */
169 for (ldenA = lista; ldenA != NULL; ldenA = ldenA->next) {
171 for (ldenB = listb; ldenB != NULL; ldenB = ldenB->next) {
172 if (ldenB->loader == ldenA->loader)
176 /* this loader is only in lista */
178 chain = &(ldenA->next);
181 /* XXX free the duplicated element */
185 /* concat listb to the result */
192 /* classcache_lookup_name ******************************************************
194 Lookup a name in the first level of the cache
195 (internally used helper function)
198 name.............the name to look up
201 a pointer to the classcache_name_entry for this name, or
202 null if no entry was found.
204 *******************************************************************************/
206 static classcache_name_entry *classcache_lookup_name(utf *name)
208 classcache_name_entry *c; /* hash table element */
209 u4 key; /* hashkey computed from classname */
210 u4 slot; /* slot in hashtable */
213 key = utf_hashkey(name->text, (u4) name->blength);
214 slot = key & (classcache_hash.size - 1);
215 c = classcache_hash.ptr[slot];
217 /* search external hash chain for the entry */
220 /* entry found in hashtable */
225 c = c->hashlink; /* next element in external chain */
234 /* classcache_new_name *********************************************************
236 Return a classcache_name_entry for the given name. The entry is created
237 if it is not already in the cache.
238 (internally used helper function)
241 name.............the name to look up / create an entry for
244 a pointer to the classcache_name_entry for this name
246 *******************************************************************************/
248 static classcache_name_entry *classcache_new_name(utf *name)
250 classcache_name_entry *c; /* hash table element */
251 u4 key; /* hashkey computed from classname */
252 u4 slot; /* slot in hashtable */
255 key = utf_hashkey(name->text, (u4) name->blength);
256 slot = key & (classcache_hash.size - 1);
257 c = classcache_hash.ptr[slot];
259 /* search external hash chain for the entry */
262 /* entry found in hashtable */
267 c = c->hashlink; /* next element in external chain */
270 /* location in hashtable found, create new entry */
272 c = NEW(classcache_name_entry);
277 /* insert entry into hashtable */
278 c->hashlink = (classcache_name_entry *) classcache_hash.ptr[slot];
279 classcache_hash.ptr[slot] = c;
281 /* update number of hashtable-entries */
282 classcache_hash.entries++;
284 if (classcache_hash.entries > (classcache_hash.size * 2)) {
286 /* reorganization of hashtable, average length of
287 the external chains is approx. 2 */
289 classcache_name_entry *c2;
290 hashtable newhash; /* the new hashtable */
292 /* create new hashtable, double the size */
294 init_hashtable(&newhash, classcache_hash.size * 2);
295 newhash.entries = classcache_hash.entries;
297 /* transfer elements to new hashtable */
299 for (i = 0; i < classcache_hash.size; i++) {
300 c2 = (classcache_name_entry *) classcache_hash.ptr[i];
302 classcache_name_entry *nextc = c2->hashlink;
304 (utf_hashkey(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
306 c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
307 newhash.ptr[newslot] = c2;
313 /* dispose old table */
315 MFREE(classcache_hash.ptr, void *, classcache_hash.size);
316 classcache_hash = newhash;
323 /* classcache_lookup ***********************************************************
325 Lookup a possibly loaded class
328 initloader.......initiating loader for resolving the class name
329 classname........class name to look up
332 The return value is a pointer to the cached class object,
333 or NULL, if the class is not in the cache.
335 Note: synchronized with global tablelock
337 *******************************************************************************/
339 classinfo *classcache_lookup(classloader *initloader, utf *classname)
341 classcache_name_entry *en;
342 classcache_class_entry *clsen;
343 classcache_loader_entry *lden;
344 classinfo *cls = NULL;
348 en = classcache_lookup_name(classname);
351 /* iterate over all class entries */
353 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
354 /* check if this entry has been loaded by initloader */
356 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
357 if (lden->loader == initloader) {
358 /* found the loaded class entry */
360 CLASSCACHE_ASSERT(clsen->classobj != NULL);
361 cls = clsen->classobj;
374 /* classcache_lookup_defined ***************************************************
376 Lookup a class with the given name and defining loader
379 defloader........defining loader
380 classname........class name
383 The return value is a pointer to the cached class object,
384 or NULL, if the class is not in the cache.
386 *******************************************************************************/
388 classinfo *classcache_lookup_defined(classloader *defloader, utf *classname)
390 classcache_name_entry *en;
391 classcache_class_entry *clsen;
392 classinfo *cls = NULL;
396 en = classcache_lookup_name(classname);
399 /* iterate over all class entries */
400 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
401 if (!clsen->classobj)
404 /* check if this entry has been defined by defloader */
405 if (clsen->classobj->classloader == defloader) {
406 cls = clsen->classobj;
418 /* classcache_store ************************************************************
420 Store a loaded class. If a class of the same name has already been stored
421 with the same initiating loader, then the given class CLS is freed (if
422 possible) and the previously stored class is returned.
425 initloader.......initiating loader used to load the class
426 (may be NULL indicating the bootstrap loader)
427 cls..............class object to cache
428 mayfree..........true if CLS may be freed in case another class is
432 cls..............everything ok, the class was stored in the cache,
433 other classinfo..another class with the same (initloader,name) has been
434 stored earlier. CLS has been freed and the earlier
435 stored class is returned.
436 NULL.............an exception has been thrown.
438 Note: synchronized with global tablelock
440 *******************************************************************************/
442 /*@shared@*/ /*@null@*/ classinfo *
444 /*@shared@*/ /*@null@*/ classloader * initloader,
445 /*@shared@*/ classinfo * cls,
448 classcache_name_entry *en;
449 classcache_class_entry *clsen;
450 classcache_loader_entry *lden;
451 #ifdef CLASSCACHE_VERBOSE
452 char logbuffer[1024];
455 CLASSCACHE_ASSERT(cls != NULL);
456 CLASSCACHE_ASSERT(cls->loaded != 0);
460 #ifdef CLASSCACHE_VERBOSE
461 sprintf(logbuffer,"classcache_store (%p,%d,", (void*)initloader,mayfree);
462 utf_strcat(logbuffer, cls->name);
463 strcat(logbuffer,")");
467 en = classcache_new_name(cls->name);
469 CLASSCACHE_ASSERT(en != NULL);
471 /* iterate over all class entries */
472 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
474 /* check if this entry has already been loaded by initloader */
475 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
476 if (lden->loader == initloader) {
477 /* A class with the same (initloader,name) pair has been stored already. */
478 /* We free the given class and return the earlier one. */
479 #ifdef CLASSCACHE_VERBOSE
480 dolog("replacing %p with earlier loaded class %p",cls,clsen->classobj);
482 CLASSCACHE_ASSERT(clsen->classobj != NULL);
485 cls = clsen->classobj;
490 /* check if initloader is constrained to this entry */
491 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
492 if (lden->loader == initloader) {
493 /* we have to use this entry */
494 /* check if is has already been resolved to another class */
495 if (clsen->classobj != NULL && clsen->classobj != cls) {
496 /* a loading constraint is violated */
497 *exceptionptr = new_exception_message(string_java_lang_LinkageError,
498 "loading constraint violated XXX add message");
499 goto return_exception;
502 /* record initloader as initiating loader */
503 clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
505 /* record the loaded class object */
506 clsen->classobj = cls;
515 /* create a new class entry for this class object with */
516 /* initiating loader initloader */
518 clsen = NEW(classcache_class_entry);
519 clsen->classobj = cls;
520 clsen->loaders = classcache_new_loader_entry(initloader, NULL);
521 clsen->constraints = NULL;
523 clsen->next = en->classes;
532 return NULL; /* exception */
535 /* classcache_store_unique *****************************************************
537 Store a loaded class as loaded by the bootstrap loader. This is a wrapper
538 aroung classcache_store that throws an exception if a class with the same
539 name has already been loaded by the bootstrap loader.
541 This function is used to register a few special classes during startup.
542 It should not be used otherwise.
545 cls..............class object to cache
548 true.............everything ok, the class was stored.
549 false............an exception has been thrown.
551 Note: synchronized with global tablelock
553 *******************************************************************************/
556 classcache_store_unique(
557 /*@shared@*/ classinfo *cls)
559 /*@shared@*/ classinfo *result;
561 result = classcache_store(NULL,cls,false);
566 *exceptionptr = new_internalerror("class already stored in the class cache");
573 /* classcache_store_defined ****************************************************
575 Store a loaded class after it has been defined. If the class has already
576 been defined by the same defining loader in another thread, free the given
577 class and returned the one which has been defined earlier.
580 cls..............class object to store. classloader must be set
581 (classloader may be NULL, for bootloader)
584 cls..............everything ok, the class was stored the cache,
585 other classinfo..the class had already been defined, CLS was freed, the
586 class which was defined earlier is returned,
587 NULL.............an exception has been thrown.
589 *******************************************************************************/
591 /*@shared@*/ /*@null@*/ classinfo *
592 classcache_store_defined(/*@shared@*/ classinfo *cls)
594 classcache_name_entry *en;
595 classcache_class_entry *clsen;
596 #ifdef CLASSCACHE_VERBOSE
597 char logbuffer[1024];
600 CLASSCACHE_ASSERT(cls != NULL);
601 CLASSCACHE_ASSERT(cls->loaded != 0);
605 #ifdef CLASSCACHE_VERBOSE
606 sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
607 utf_strcat(logbuffer, cls->name);
608 strcat(logbuffer,")");
612 en = classcache_new_name(cls->name);
614 CLASSCACHE_ASSERT(en != NULL);
616 /* iterate over all class entries */
617 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
619 /* check if this class has been defined by the same classloader */
620 if (clsen->classobj != NULL && clsen->classobj->classloader == cls->classloader) {
621 /* we found an earlier definition, delete the newer one */
622 /* (if it is a different classinfo) */
623 if (clsen->classobj != cls) {
624 #ifdef CLASSCACHE_VERBOSE
625 dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
628 cls = clsen->classobj;
634 /* create a new class entry for this class object */
635 /* the list of initiating loaders is empty at this point */
637 clsen = NEW(classcache_class_entry);
638 clsen->classobj = cls;
639 clsen->loaders = NULL;
640 clsen->constraints = NULL;
642 clsen->next = en->classes;
650 /* classcache_find_loader ******************************************************
652 Find the class entry loaded by or constrained to a given loader
653 (internally used helper function)
656 entry............the classcache_name_entry
657 loader...........the loader to look for
660 the classcache_class_entry for the given loader, or
661 NULL if no entry was found
663 *******************************************************************************/
665 static /*@exposed@*/ /*@null@*/ classcache_class_entry *
666 classcache_find_loader(
667 classcache_name_entry * entry,
668 /*@shared@*/ /*@null@*/ classloader * loader)
670 classcache_class_entry *clsen;
671 classcache_loader_entry *lden;
673 CLASSCACHE_ASSERT(entry != NULL);
675 /* iterate over all class entries */
676 for (clsen = entry->classes; clsen != NULL; clsen = clsen->next) {
678 /* check if this entry has already been loaded by initloader */
679 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
680 if (lden->loader == loader)
681 return clsen; /* found */
684 /* check if loader is constrained to this entry */
685 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
686 if (lden->loader == loader)
687 return clsen; /* found */
695 /* classcache_free_class_entry *************************************************
697 Free the memory used by a class entry
700 clsen............the classcache_class_entry to free
702 *******************************************************************************/
705 classcache_free_class_entry(
706 classcache_class_entry * clsen)
708 classcache_loader_entry *lden;
709 classcache_loader_entry *next;
711 CLASSCACHE_ASSERT(clsen != NULL);
713 for (lden = clsen->loaders; lden != NULL; lden = next) {
715 FREE(lden, classcache_loader_entry);
717 for (lden = clsen->constraints; lden != NULL; lden = next) {
719 FREE(lden, classcache_loader_entry);
722 FREE(clsen, classcache_class_entry);
725 /* classcache_remove_class_entry ***********************************************
727 Remove a classcache_class_entry from the list of possible resolution of
729 (internally used helper function)
732 entry............the classcache_name_entry
733 clsen............the classcache_class_entry to remove
735 *******************************************************************************/
738 classcache_remove_class_entry(
739 classcache_name_entry * entry,
740 classcache_class_entry * clsen)
742 classcache_class_entry **chain;
744 CLASSCACHE_ASSERT(entry != NULL);
745 CLASSCACHE_ASSERT(clsen != NULL);
747 chain = &(entry->classes);
749 if (*chain == clsen) {
750 *chain = clsen->next;
751 classcache_free_class_entry(clsen);
754 chain = &((*chain)->next);
758 /* classcache_free_name_entry **************************************************
760 Free the memory used by a name entry
763 entry............the classcache_name_entry to free
765 *******************************************************************************/
768 classcache_free_name_entry(
769 classcache_name_entry * entry)
771 classcache_class_entry *clsen;
772 classcache_class_entry *next;
774 CLASSCACHE_ASSERT(entry != NULL);
776 for (clsen = entry->classes; clsen; clsen = next) {
778 classcache_free_class_entry(clsen);
781 FREE(entry, classcache_name_entry);
784 /* classcache_free *************************************************************
786 Free the memory used by the class cache
789 The class cache may not be used any more after this call, except
790 when it is reinitialized with classcache_init.
792 Note: NOT synchronized!
794 *******************************************************************************/
799 /*@globals killed classcache_hash@*/
802 classcache_name_entry *entry;
803 classcache_name_entry *next;
805 for (slot = 0; slot < classcache_hash.size; ++slot) {
806 for (entry = (classcache_name_entry *) classcache_hash.ptr[slot]; entry; entry = next) {
807 next = entry->hashlink;
808 classcache_free_name_entry(entry);
812 MFREE(classcache_hash.ptr, voidptr, classcache_hash.size);
813 classcache_hash.size = 0;
814 classcache_hash.entries = 0;
815 classcache_hash.ptr = NULL;
818 /* classcache_add_constraint ***************************************************
820 Add a loading constraint
823 a................first initiating loader
824 b................second initiating loader
825 classname........class name
828 true.............everything ok, the constraint has been added,
829 false............an exception has been thrown.
831 Note: synchronized with global tablelock
833 *******************************************************************************/
836 classcache_add_constraint(
837 /*@shared@*/ /*@null@*/ classloader * a,
838 /*@shared@*/ /*@null@*/ classloader * b,
839 /*@shared@*/ utf * classname)
841 classcache_name_entry *en;
842 classcache_class_entry *clsenA;
843 classcache_class_entry *clsenB;
845 CLASSCACHE_ASSERT(classname != NULL);
847 #ifdef CLASSCACHE_VERBOSE
848 fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
849 utf_fprint_classname(stderr, classname);
850 fprintf(stderr, ")\n");
853 /* a constraint with a == b is trivially satisfied */
859 en = classcache_new_name(classname);
861 CLASSCACHE_ASSERT(en != NULL);
863 /* find the entry loaded by / constrained to each loader */
864 clsenA = classcache_find_loader(en, a);
865 clsenB = classcache_find_loader(en, b);
867 if (clsenA != NULL && clsenB != NULL) {
868 /* { both loaders have corresponding entries } */
870 /* if the entries are the same, the constraint is already recorded */
871 if (clsenA == clsenB)
874 /* check if the entries can be merged */
875 if (clsenA->classobj != NULL && clsenB->classobj != NULL
876 && clsenA->classobj != clsenB->classobj) {
877 /* no, the constraint is violated */
878 *exceptionptr = new_exception_message(string_java_lang_LinkageError,
879 "loading constraint violated XXX add message");
880 goto return_exception;
883 /* yes, merge the entries */
884 /* clsenB will be merged into clsenA */
885 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
886 clsenB->loaders = NULL;
888 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
889 clsenB->constraints);
890 clsenB->constraints = NULL;
892 if (!clsenA->classobj)
893 clsenA->classobj = clsenB->classobj;
895 /* remove clsenB from the list of class entries */
896 classcache_remove_class_entry(en, clsenB);
899 /* { at most one of the loaders has a corresponding entry } */
901 /* set clsenA to the single class entry we have */
906 /* { no loader has a corresponding entry } */
908 /* create a new class entry with the constraint (a,b,en->name) */
909 clsenA = NEW(classcache_class_entry);
910 clsenA->classobj = NULL;
911 clsenA->loaders = NULL;
912 clsenA->constraints = classcache_new_loader_entry(b, NULL);
913 clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
915 clsenA->next = en->classes;
916 en->classes = clsenA;
919 /* make b the loader that has no corresponding entry */
923 /* loader b must be added to entry clsenA */
924 clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
934 return false; /* exception */
937 /*============================================================================*/
939 /*============================================================================*/
941 /* classcache_debug_dump *******************************************************
943 Print the contents of the loaded class cache to a stream
946 file.............output stream
948 Note: synchronized with global tablelock
950 *******************************************************************************/
953 classcache_debug_dump(
954 /*@shared@*/ FILE * file)
956 classcache_name_entry *c;
957 classcache_class_entry *clsen;
958 classcache_loader_entry *lden;
963 fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
964 fprintf(file, "hash size : %d\n", (int) classcache_hash.size);
965 fprintf(file, "hash entries: %d\n", (int) classcache_hash.entries);
968 for (slot = 0; slot < classcache_hash.size; ++slot) {
969 c = (classcache_name_entry *) classcache_hash.ptr[slot];
971 for (; c != NULL; c = c->hashlink) {
972 utf_fprint_classname(file, c->name);
975 /* iterate over all class entries */
976 for (clsen = c->classes; clsen != NULL; clsen = clsen->next) {
977 if (clsen->classobj) {
978 fprintf(file, " loaded %p\n", (void *) clsen->classobj);
981 fprintf(file, " unresolved\n");
983 fprintf(file, " loaders:");
984 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
985 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
987 fprintf(file, "\n constraints:");
988 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
989 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
995 fprintf(file, "\n==============================================================\n\n");
1001 * These are local overrides for various environment variables in Emacs.
1002 * Please do not remove this and leave it at the end of the file, where
1003 * Emacs will automagically detect them.
1004 * ---------------------------------------------------------------------
1007 * indent-tabs-mode: t
1011 * vim:noexpandtab:sw=4:ts=4: