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 3263 2005-09-21 20:18:03Z twisti $
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 #ifdef CLASSCACHE_VERBOSE
623 dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
625 /* we assert that the earlier object is not the same that we were given */
626 CLASSCACHE_ASSERT(clsen->classobj != cls);
628 cls = clsen->classobj;
633 /* create a new class entry for this class object */
634 /* the list of initiating loaders is empty at this point */
636 clsen = NEW(classcache_class_entry);
637 clsen->classobj = cls;
638 clsen->loaders = NULL;
639 clsen->constraints = NULL;
641 clsen->next = en->classes;
649 /* classcache_find_loader ******************************************************
651 Find the class entry loaded by or constrained to a given loader
652 (internally used helper function)
655 entry............the classcache_name_entry
656 loader...........the loader to look for
659 the classcache_class_entry for the given loader, or
660 NULL if no entry was found
662 *******************************************************************************/
664 static /*@exposed@*/ /*@null@*/ classcache_class_entry *
665 classcache_find_loader(
666 classcache_name_entry * entry,
667 /*@shared@*/ /*@null@*/ classloader * loader)
669 classcache_class_entry *clsen;
670 classcache_loader_entry *lden;
672 CLASSCACHE_ASSERT(entry != NULL);
674 /* iterate over all class entries */
675 for (clsen = entry->classes; clsen != NULL; clsen = clsen->next) {
677 /* check if this entry has already been loaded by initloader */
678 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
679 if (lden->loader == loader)
680 return clsen; /* found */
683 /* check if loader is constrained to this entry */
684 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
685 if (lden->loader == loader)
686 return clsen; /* found */
694 /* classcache_free_class_entry *************************************************
696 Free the memory used by a class entry
699 clsen............the classcache_class_entry to free
701 *******************************************************************************/
704 classcache_free_class_entry(
705 classcache_class_entry * clsen)
707 classcache_loader_entry *lden;
708 classcache_loader_entry *next;
710 CLASSCACHE_ASSERT(clsen != NULL);
712 for (lden = clsen->loaders; lden != NULL; lden = next) {
714 FREE(lden, classcache_loader_entry);
716 for (lden = clsen->constraints; lden != NULL; lden = next) {
718 FREE(lden, classcache_loader_entry);
721 FREE(clsen, classcache_class_entry);
724 /* classcache_remove_class_entry ***********************************************
726 Remove a classcache_class_entry from the list of possible resolution of
728 (internally used helper function)
731 entry............the classcache_name_entry
732 clsen............the classcache_class_entry to remove
734 *******************************************************************************/
737 classcache_remove_class_entry(
738 classcache_name_entry * entry,
739 classcache_class_entry * clsen)
741 classcache_class_entry **chain;
743 CLASSCACHE_ASSERT(entry != NULL);
744 CLASSCACHE_ASSERT(clsen != NULL);
746 chain = &(entry->classes);
748 if (*chain == clsen) {
749 *chain = clsen->next;
750 classcache_free_class_entry(clsen);
753 chain = &((*chain)->next);
757 /* classcache_free_name_entry **************************************************
759 Free the memory used by a name entry
762 entry............the classcache_name_entry to free
764 *******************************************************************************/
767 classcache_free_name_entry(
768 classcache_name_entry * entry)
770 classcache_class_entry *clsen;
771 classcache_class_entry *next;
773 CLASSCACHE_ASSERT(entry != NULL);
775 for (clsen = entry->classes; clsen; clsen = next) {
777 classcache_free_class_entry(clsen);
780 FREE(entry, classcache_name_entry);
783 /* classcache_free *************************************************************
785 Free the memory used by the class cache
788 The class cache may not be used any more after this call, except
789 when it is reinitialized with classcache_init.
791 Note: NOT synchronized!
793 *******************************************************************************/
798 /*@globals killed classcache_hash@*/
801 classcache_name_entry *entry;
802 classcache_name_entry *next;
804 for (slot = 0; slot < classcache_hash.size; ++slot) {
805 for (entry = (classcache_name_entry *) classcache_hash.ptr[slot]; entry; entry = next) {
806 next = entry->hashlink;
807 classcache_free_name_entry(entry);
811 MFREE(classcache_hash.ptr, voidptr, classcache_hash.size);
812 classcache_hash.size = 0;
813 classcache_hash.entries = 0;
814 classcache_hash.ptr = NULL;
817 /* classcache_add_constraint ***************************************************
819 Add a loading constraint
822 a................first initiating loader
823 b................second initiating loader
824 classname........class name
827 true.............everything ok, the constraint has been added,
828 false............an exception has been thrown.
830 Note: synchronized with global tablelock
832 *******************************************************************************/
835 classcache_add_constraint(
836 /*@shared@*/ /*@null@*/ classloader * a,
837 /*@shared@*/ /*@null@*/ classloader * b,
838 /*@shared@*/ utf * classname)
840 classcache_name_entry *en;
841 classcache_class_entry *clsenA;
842 classcache_class_entry *clsenB;
844 CLASSCACHE_ASSERT(classname != NULL);
846 #ifdef CLASSCACHE_VERBOSE
847 fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
848 utf_fprint_classname(stderr, classname);
849 fprintf(stderr, ")\n");
852 /* a constraint with a == b is trivially satisfied */
858 en = classcache_new_name(classname);
860 CLASSCACHE_ASSERT(en != NULL);
862 /* find the entry loaded by / constrained to each loader */
863 clsenA = classcache_find_loader(en, a);
864 clsenB = classcache_find_loader(en, b);
866 if (clsenA != NULL && clsenB != NULL) {
867 /* { both loaders have corresponding entries } */
869 /* if the entries are the same, the constraint is already recorded */
870 if (clsenA == clsenB)
873 /* check if the entries can be merged */
874 if (clsenA->classobj != NULL && clsenB->classobj != NULL
875 && clsenA->classobj != clsenB->classobj) {
876 /* no, the constraint is violated */
877 *exceptionptr = new_exception_message(string_java_lang_LinkageError,
878 "loading constraint violated XXX add message");
879 goto return_exception;
882 /* yes, merge the entries */
883 /* clsenB will be merged into clsenA */
884 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
885 clsenB->loaders = NULL;
887 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
888 clsenB->constraints);
889 clsenB->constraints = NULL;
891 if (!clsenA->classobj)
892 clsenA->classobj = clsenB->classobj;
894 /* remove clsenB from the list of class entries */
895 classcache_remove_class_entry(en, clsenB);
898 /* { at most one of the loaders has a corresponding entry } */
900 /* set clsenA to the single class entry we have */
905 /* { no loader has a corresponding entry } */
907 /* create a new class entry with the constraint (a,b,en->name) */
908 clsenA = NEW(classcache_class_entry);
909 clsenA->classobj = NULL;
910 clsenA->loaders = NULL;
911 clsenA->constraints = classcache_new_loader_entry(b, NULL);
912 clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
914 clsenA->next = en->classes;
915 en->classes = clsenA;
918 /* make b the loader that has no corresponding entry */
922 /* loader b must be added to entry clsenA */
923 clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
933 return false; /* exception */
936 /*============================================================================*/
938 /*============================================================================*/
940 /* classcache_debug_dump *******************************************************
942 Print the contents of the loaded class cache to a stream
945 file.............output stream
947 Note: synchronized with global tablelock
949 *******************************************************************************/
952 classcache_debug_dump(
953 /*@shared@*/ FILE * file)
955 classcache_name_entry *c;
956 classcache_class_entry *clsen;
957 classcache_loader_entry *lden;
962 fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
963 fprintf(file, "hash size : %d\n", (int) classcache_hash.size);
964 fprintf(file, "hash entries: %d\n", (int) classcache_hash.entries);
967 for (slot = 0; slot < classcache_hash.size; ++slot) {
968 c = (classcache_name_entry *) classcache_hash.ptr[slot];
970 for (; c != NULL; c = c->hashlink) {
971 utf_fprint_classname(file, c->name);
974 /* iterate over all class entries */
975 for (clsen = c->classes; clsen != NULL; clsen = clsen->next) {
976 if (clsen->classobj) {
977 fprintf(file, " loaded %p\n", (void *) clsen->classobj);
980 fprintf(file, " unresolved\n");
982 fprintf(file, " loaders:");
983 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
984 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
986 fprintf(file, "\n constraints:");
987 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
988 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
994 fprintf(file, "\n==============================================================\n\n");
1000 * These are local overrides for various environment variables in Emacs.
1001 * Please do not remove this and leave it at the end of the file, where
1002 * Emacs will automagically detect them.
1003 * ---------------------------------------------------------------------
1006 * indent-tabs-mode: t
1010 * vim:noexpandtab:sw=4:ts=4: