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 3814 2005-11-28 18:51:26Z 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*/
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_classcache_hashtable)
69 # define CLASSCACHE_UNLOCK() builtin_monitorexit(lock_classcache_hashtable)
71 # define CLASSCACHE_LOCK()
72 # define CLASSCACHE_UNLOCK()
75 /*============================================================================*/
76 /* GLOBAL VARIABLES */
77 /*============================================================================*/
79 #if defined(USE_THREADS)
80 static java_objectheader *lock_classcache_hashtable;
83 hashtable classcache_hash;
85 /*============================================================================*/
87 /*============================================================================*/
89 /* classcache_init *************************************************************
91 Initialize the loaded class cache
93 Note: NOT synchronized!
95 *******************************************************************************/
97 bool classcache_init(void)
99 #if defined(USE_THREADS)
100 /* create utf hashtable lock object */
102 lock_classcache_hashtable = NEW(java_objectheader);
104 # if defined(NATIVE_THREADS)
105 initObjectLock(lock_classcache_hashtable);
109 init_hashtable(&classcache_hash, CLASSCACHE_INIT_SIZE);
111 /* everything's ok */
116 /* classcache_new_loader_entry *************************************************
118 Create a new classcache_loader_entry struct
119 (internally used helper function)
122 loader...........the ClassLoader object
123 next.............the next classcache_loader_entry
126 the new classcache_loader_entry
128 *******************************************************************************/
130 static classcache_loader_entry * classcache_new_loader_entry(
131 classloader * loader,
132 classcache_loader_entry * next)
134 classcache_loader_entry *lden;
136 lden = NEW(classcache_loader_entry);
137 lden->loader = loader;
143 /* classcache_merge_loaders ****************************************************
145 Merge two lists of loaders into one
146 (internally used helper function)
149 lista............first list (may be NULL)
150 listb............second list (may be NULL)
153 the merged list (may be NULL)
156 The lists given as arguments are destroyed!
158 *******************************************************************************/
160 static classcache_loader_entry * classcache_merge_loaders(
161 classcache_loader_entry * lista,
162 classcache_loader_entry * listb)
164 classcache_loader_entry *result;
165 classcache_loader_entry *ldenA;
166 classcache_loader_entry *ldenB;
167 classcache_loader_entry **chain;
169 /* XXX This is a quadratic algorithm. If this ever
170 * becomes a problem, the loader lists should be
171 * stored as sorted lists and merged in linear time. */
176 for (ldenA = lista; ldenA; ldenA = ldenA->next) {
178 for (ldenB = listb; ldenB; ldenB = ldenB->next) {
179 if (ldenB->loader == ldenA->loader)
183 /* this loader is only in lista */
185 chain = &(ldenA->next);
188 /* XXX free the duplicated element */
192 /* concat listb to the result */
199 /* classcache_lookup_name ******************************************************
201 Lookup a name in the first level of the cache
202 (internally used helper function)
205 name.............the name to look up
208 a pointer to the classcache_name_entry for this name, or
209 null if no entry was found.
211 *******************************************************************************/
213 static classcache_name_entry *classcache_lookup_name(utf *name)
215 classcache_name_entry *c; /* hash table element */
216 u4 key; /* hashkey computed from classname */
217 u4 slot; /* slot in hashtable */
220 key = utf_hashkey(name->text, (u4) name->blength);
221 slot = key & (classcache_hash.size - 1);
222 c = classcache_hash.ptr[slot];
224 /* search external hash chain for the entry */
227 /* entry found in hashtable */
232 c = c->hashlink; /* next element in external chain */
241 /* classcache_new_name *********************************************************
243 Return a classcache_name_entry for the given name. The entry is created
244 if it is not already in the cache.
245 (internally used helper function)
248 name.............the name to look up / create an entry for
251 a pointer to the classcache_name_entry for this name
253 *******************************************************************************/
255 static classcache_name_entry *classcache_new_name(utf *name)
257 classcache_name_entry *c; /* hash table element */
258 u4 key; /* hashkey computed from classname */
259 u4 slot; /* slot in hashtable */
262 key = utf_hashkey(name->text, (u4) name->blength);
263 slot = key & (classcache_hash.size - 1);
264 c = classcache_hash.ptr[slot];
266 /* search external hash chain for the entry */
269 /* entry found in hashtable */
274 c = c->hashlink; /* next element in external chain */
277 /* location in hashtable found, create new entry */
279 c = NEW(classcache_name_entry);
284 /* insert entry into hashtable */
285 c->hashlink = (classcache_name_entry *) classcache_hash.ptr[slot];
286 classcache_hash.ptr[slot] = c;
288 /* update number of hashtable-entries */
289 classcache_hash.entries++;
291 if (classcache_hash.entries > (classcache_hash.size * 2)) {
293 /* reorganization of hashtable, average length of
294 the external chains is approx. 2 */
296 classcache_name_entry *c2;
297 hashtable newhash; /* the new hashtable */
299 /* create new hashtable, double the size */
301 init_hashtable(&newhash, classcache_hash.size * 2);
302 newhash.entries = classcache_hash.entries;
304 /* transfer elements to new hashtable */
306 for (i = 0; i < classcache_hash.size; i++) {
307 c2 = (classcache_name_entry *) classcache_hash.ptr[i];
309 classcache_name_entry *nextc = c2->hashlink;
311 (utf_hashkey(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
313 c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
314 newhash.ptr[newslot] = c2;
320 /* dispose old table */
322 MFREE(classcache_hash.ptr, void *, classcache_hash.size);
323 classcache_hash = newhash;
330 /* classcache_lookup ***********************************************************
332 Lookup a possibly loaded class
335 initloader.......initiating loader for resolving the class name
336 classname........class name to look up
339 The return value is a pointer to the cached class object,
340 or NULL, if the class is not in the cache.
342 Note: synchronized with global tablelock
344 *******************************************************************************/
346 classinfo *classcache_lookup(classloader *initloader, utf *classname)
348 classcache_name_entry *en;
349 classcache_class_entry *clsen;
350 classcache_loader_entry *lden;
351 classinfo *cls = NULL;
355 en = classcache_lookup_name(classname);
358 /* iterate over all class entries */
360 for (clsen = en->classes; clsen; clsen = clsen->next) {
361 /* check if this entry has been loaded by initloader */
363 for (lden = clsen->loaders; lden; lden = lden->next) {
364 if (lden->loader == initloader) {
365 /* found the loaded class entry */
367 assert(clsen->classobj);
368 cls = clsen->classobj;
381 /* classcache_lookup_defined ***************************************************
383 Lookup a class with the given name and defining loader
386 defloader........defining loader
387 classname........class name
390 The return value is a pointer to the cached class object,
391 or NULL, if the class is not in the cache.
393 *******************************************************************************/
395 classinfo *classcache_lookup_defined(classloader *defloader, utf *classname)
397 classcache_name_entry *en;
398 classcache_class_entry *clsen;
399 classinfo *cls = NULL;
403 en = classcache_lookup_name(classname);
406 /* iterate over all class entries */
407 for (clsen = en->classes; clsen; clsen = clsen->next) {
408 if (!clsen->classobj)
411 /* check if this entry has been defined by defloader */
412 if (clsen->classobj->classloader == defloader) {
413 cls = clsen->classobj;
425 /* classcache_lookup_defined_or_initiated **************************************
427 Lookup a class that has been defined or initiated by the given loader
430 loader...........defining or initiating loader
431 classname........class name to look up
434 The return value is a pointer to the cached class object,
435 or NULL, if the class is not in the cache.
437 Note: synchronized with global tablelock
439 *******************************************************************************/
441 classinfo *classcache_lookup_defined_or_initiated(classloader *loader,
444 classcache_name_entry *en;
445 classcache_class_entry *clsen;
446 classcache_loader_entry *lden;
447 classinfo *cls = NULL;
451 en = classcache_lookup_name(classname);
454 /* iterate over all class entries */
456 for (clsen = en->classes; clsen; clsen = clsen->next) {
458 /* check if this entry has been defined by loader */
459 if (clsen->classobj && clsen->classobj->classloader == loader) {
460 cls = clsen->classobj;
464 /* check if this entry has been initiated by loader */
465 for (lden = clsen->loaders; lden; lden = lden->next) {
466 if (lden->loader == loader) {
467 /* found the loaded class entry */
469 assert(clsen->classobj);
470 cls = clsen->classobj;
483 /* classcache_store ************************************************************
485 Store a loaded class. If a class of the same name has already been stored
486 with the same initiating loader, then the given class CLS is freed (if
487 possible) and the previously stored class is returned.
490 initloader.......initiating loader used to load the class
491 (may be NULL indicating the bootstrap loader)
492 cls..............class object to cache
493 mayfree..........true if CLS may be freed in case another class is
497 cls..............everything ok, the class was stored in the cache,
498 other classinfo..another class with the same (initloader,name) has been
499 stored earlier. CLS has been freed and the earlier
500 stored class is returned.
501 NULL.............an exception has been thrown.
503 Note: synchronized with global tablelock
505 *******************************************************************************/
507 classinfo * classcache_store(classloader * initloader,
511 classcache_name_entry *en;
512 classcache_class_entry *clsen;
513 classcache_loader_entry *lden;
514 #ifdef CLASSCACHE_VERBOSE
515 char logbuffer[1024];
519 assert(cls->loaded != 0);
523 #ifdef CLASSCACHE_VERBOSE
524 sprintf(logbuffer,"classcache_store (%p,%d,", (void*)initloader,mayfree);
525 utf_strcat(logbuffer, cls->name);
526 strcat(logbuffer,")");
530 en = classcache_new_name(cls->name);
534 /* iterate over all class entries */
535 for (clsen = en->classes; clsen; clsen = clsen->next) {
537 /* check if this entry has already been loaded by initloader */
538 for (lden = clsen->loaders; lden; lden = lden->next) {
539 if (lden->loader == initloader && clsen->classobj != cls) {
540 /* A class with the same (initloader,name) pair has been stored already. */
541 /* We free the given class and return the earlier one. */
542 #ifdef CLASSCACHE_VERBOSE
543 dolog("replacing %p with earlier loaded class %p",cls,clsen->classobj);
545 assert(clsen->classobj);
548 cls = clsen->classobj;
553 /* check if initloader is constrained to this entry */
554 for (lden = clsen->constraints; lden; lden = lden->next) {
555 if (lden->loader == initloader) {
556 /* we have to use this entry */
557 /* check if is has already been resolved to another class */
558 if (clsen->classobj && clsen->classobj != cls) {
559 /* a loading constraint is violated */
560 *exceptionptr = exceptions_new_linkageerror(
561 "loading constraint violated: ",cls);
562 goto return_exception;
565 /* record initloader as initiating loader */
566 clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
568 /* record the loaded class object */
569 clsen->classobj = cls;
578 /* create a new class entry for this class object with */
579 /* initiating loader initloader */
581 clsen = NEW(classcache_class_entry);
582 clsen->classobj = cls;
583 clsen->loaders = classcache_new_loader_entry(initloader, NULL);
584 clsen->constraints = NULL;
586 clsen->next = en->classes;
595 return NULL; /* exception */
598 /* classcache_store_unique *****************************************************
600 Store a loaded class as loaded by the bootstrap loader. This is a wrapper
601 aroung classcache_store that throws an exception if a class with the same
602 name has already been loaded by the bootstrap loader.
604 This function is used to register a few special classes during startup.
605 It should not be used otherwise.
608 cls..............class object to cache
611 true.............everything ok, the class was stored.
612 false............an exception has been thrown.
614 Note: synchronized with global tablelock
616 *******************************************************************************/
618 bool classcache_store_unique(classinfo *cls)
622 result = classcache_store(NULL,cls,false);
627 *exceptionptr = new_internalerror("class already stored in the class cache");
634 /* classcache_store_defined ****************************************************
636 Store a loaded class after it has been defined. If the class has already
637 been defined by the same defining loader in another thread, free the given
638 class and returned the one which has been defined earlier.
641 cls..............class object to store. classloader must be set
642 (classloader may be NULL, for bootloader)
645 cls..............everything ok, the class was stored the cache,
646 other classinfo..the class had already been defined, CLS was freed, the
647 class which was defined earlier is returned,
648 NULL.............an exception has been thrown.
650 *******************************************************************************/
652 classinfo * classcache_store_defined(classinfo *cls)
654 classcache_name_entry *en;
655 classcache_class_entry *clsen;
656 #ifdef CLASSCACHE_VERBOSE
657 char logbuffer[1024];
661 assert(cls->loaded != 0);
665 #ifdef CLASSCACHE_VERBOSE
666 sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
667 utf_strcat(logbuffer, cls->name);
668 strcat(logbuffer,")");
672 en = classcache_new_name(cls->name);
676 /* iterate over all class entries */
677 for (clsen = en->classes; clsen; clsen = clsen->next) {
679 /* check if this class has been defined by the same classloader */
680 if (clsen->classobj && clsen->classobj->classloader == cls->classloader) {
681 /* we found an earlier definition, delete the newer one */
682 /* (if it is a different classinfo) */
683 if (clsen->classobj != cls) {
684 #ifdef CLASSCACHE_VERBOSE
685 dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
688 cls = clsen->classobj;
694 /* create a new class entry for this class object */
695 /* the list of initiating loaders is empty at this point */
697 clsen = NEW(classcache_class_entry);
698 clsen->classobj = cls;
699 clsen->loaders = NULL;
700 clsen->constraints = NULL;
702 clsen->next = en->classes;
710 /* classcache_find_loader ******************************************************
712 Find the class entry loaded by or constrained to a given loader
713 (internally used helper function)
716 entry............the classcache_name_entry
717 loader...........the loader to look for
720 the classcache_class_entry for the given loader, or
721 NULL if no entry was found
723 *******************************************************************************/
725 static classcache_class_entry * classcache_find_loader(
726 classcache_name_entry * entry,
727 classloader * loader)
729 classcache_class_entry *clsen;
730 classcache_loader_entry *lden;
734 /* iterate over all class entries */
735 for (clsen = entry->classes; clsen; clsen = clsen->next) {
737 /* check if this entry has already been loaded by initloader */
738 for (lden = clsen->loaders; lden; lden = lden->next) {
739 if (lden->loader == loader)
740 return clsen; /* found */
743 /* check if loader is constrained to this entry */
744 for (lden = clsen->constraints; lden; lden = lden->next) {
745 if (lden->loader == loader)
746 return clsen; /* found */
754 /* classcache_free_class_entry *************************************************
756 Free the memory used by a class entry
759 clsen............the classcache_class_entry to free
761 *******************************************************************************/
763 static void classcache_free_class_entry(classcache_class_entry * clsen)
765 classcache_loader_entry *lden;
766 classcache_loader_entry *next;
770 for (lden = clsen->loaders; lden; lden = next) {
772 FREE(lden, classcache_loader_entry);
774 for (lden = clsen->constraints; lden; lden = next) {
776 FREE(lden, classcache_loader_entry);
779 FREE(clsen, classcache_class_entry);
782 /* classcache_remove_class_entry ***********************************************
784 Remove a classcache_class_entry from the list of possible resolution of
786 (internally used helper function)
789 entry............the classcache_name_entry
790 clsen............the classcache_class_entry to remove
792 *******************************************************************************/
794 static void classcache_remove_class_entry(classcache_name_entry * entry,
795 classcache_class_entry * clsen)
797 classcache_class_entry **chain;
802 chain = &(entry->classes);
804 if (*chain == clsen) {
805 *chain = clsen->next;
806 classcache_free_class_entry(clsen);
809 chain = &((*chain)->next);
813 /* classcache_free_name_entry **************************************************
815 Free the memory used by a name entry
818 entry............the classcache_name_entry to free
820 *******************************************************************************/
822 static void classcache_free_name_entry(classcache_name_entry * entry)
824 classcache_class_entry *clsen;
825 classcache_class_entry *next;
829 for (clsen = entry->classes; clsen; clsen = next) {
831 classcache_free_class_entry(clsen);
834 FREE(entry, classcache_name_entry);
837 /* classcache_free *************************************************************
839 Free the memory used by the class cache
842 The class cache may not be used any more after this call, except
843 when it is reinitialized with classcache_init.
845 Note: NOT synchronized!
847 *******************************************************************************/
849 void classcache_free(void)
852 classcache_name_entry *entry;
853 classcache_name_entry *next;
855 for (slot = 0; slot < classcache_hash.size; ++slot) {
856 for (entry = (classcache_name_entry *) classcache_hash.ptr[slot]; entry; entry = next) {
857 next = entry->hashlink;
858 classcache_free_name_entry(entry);
862 MFREE(classcache_hash.ptr, voidptr, classcache_hash.size);
863 classcache_hash.size = 0;
864 classcache_hash.entries = 0;
865 classcache_hash.ptr = NULL;
868 /* classcache_add_constraint ***************************************************
870 Add a loading constraint
873 a................first initiating loader
874 b................second initiating loader
875 classname........class name
878 true.............everything ok, the constraint has been added,
879 false............an exception has been thrown.
881 Note: synchronized with global tablelock
883 *******************************************************************************/
885 bool classcache_add_constraint(classloader * a,
889 classcache_name_entry *en;
890 classcache_class_entry *clsenA;
891 classcache_class_entry *clsenB;
895 #ifdef CLASSCACHE_VERBOSE
896 fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
897 utf_fprint_classname(stderr, classname);
898 fprintf(stderr, ")\n");
901 /* a constraint with a == b is trivially satisfied */
907 en = classcache_new_name(classname);
911 /* find the entry loaded by / constrained to each loader */
912 clsenA = classcache_find_loader(en, a);
913 clsenB = classcache_find_loader(en, b);
915 if (clsenA && clsenB) {
916 /* { both loaders have corresponding entries } */
918 /* if the entries are the same, the constraint is already recorded */
919 if (clsenA == clsenB)
922 /* check if the entries can be merged */
923 if (clsenA->classobj && clsenB->classobj
924 && clsenA->classobj != clsenB->classobj) {
925 /* no, the constraint is violated */
926 *exceptionptr = exceptions_new_linkageerror(
927 "loading constraint violated: ",clsenA->classobj);
928 goto return_exception;
931 /* yes, merge the entries */
932 /* clsenB will be merged into clsenA */
933 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
934 clsenB->loaders = NULL;
936 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
937 clsenB->constraints);
938 clsenB->constraints = NULL;
940 if (!clsenA->classobj)
941 clsenA->classobj = clsenB->classobj;
943 /* remove clsenB from the list of class entries */
944 classcache_remove_class_entry(en, clsenB);
947 /* { at most one of the loaders has a corresponding entry } */
949 /* set clsenA to the single class entry we have */
954 /* { no loader has a corresponding entry } */
956 /* create a new class entry with the constraint (a,b,en->name) */
957 clsenA = NEW(classcache_class_entry);
958 clsenA->classobj = NULL;
959 clsenA->loaders = NULL;
960 clsenA->constraints = classcache_new_loader_entry(b, NULL);
961 clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
963 clsenA->next = en->classes;
964 en->classes = clsenA;
967 /* make b the loader that has no corresponding entry */
971 /* loader b must be added to entry clsenA */
972 clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
982 return false; /* exception */
985 /*============================================================================*/
987 /*============================================================================*/
989 /* classcache_debug_dump *******************************************************
991 Print the contents of the loaded class cache to a stream
994 file.............output stream
996 Note: synchronized with global tablelock
998 *******************************************************************************/
1001 void classcache_debug_dump(FILE * file)
1003 classcache_name_entry *c;
1004 classcache_class_entry *clsen;
1005 classcache_loader_entry *lden;
1010 fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
1011 fprintf(file, "hash size : %d\n", (int) classcache_hash.size);
1012 fprintf(file, "hash entries: %d\n", (int) classcache_hash.entries);
1013 fprintf(file, "\n");
1015 for (slot = 0; slot < classcache_hash.size; ++slot) {
1016 c = (classcache_name_entry *) classcache_hash.ptr[slot];
1018 for (; c; c = c->hashlink) {
1019 utf_fprint_classname(file, c->name);
1020 fprintf(file, "\n");
1022 /* iterate over all class entries */
1023 for (clsen = c->classes; clsen; clsen = clsen->next) {
1024 if (clsen->classobj) {
1025 fprintf(file, " loaded %p\n", (void *) clsen->classobj);
1028 fprintf(file, " unresolved\n");
1030 fprintf(file, " loaders:");
1031 for (lden = clsen->loaders; lden; lden = lden->next) {
1032 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1034 fprintf(file, "\n constraints:");
1035 for (lden = clsen->constraints; lden; lden = lden->next) {
1036 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
1038 fprintf(file, "\n");
1042 fprintf(file, "\n==============================================================\n\n");
1044 CLASSCACHE_UNLOCK();
1049 * These are local overrides for various environment variables in Emacs.
1050 * Please do not remove this and leave it at the end of the file, where
1051 * Emacs will automagically detect them.
1052 * ---------------------------------------------------------------------
1055 * indent-tabs-mode: t
1059 * vim:noexpandtab:sw=4:ts=4: