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 2458 2005-05-12 23:02:07Z 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 */
191 /* classcache_lookup_name ******************************************************
193 Lookup a name in the first level of the cache
194 (internally used helper function)
197 name.............the name to look up
200 a pointer to the classcache_name_entry for this name, or
201 null if no entry was found.
203 *******************************************************************************/
205 static /*@exposed@*/ /*@null@*/ classcache_name_entry *
206 classcache_lookup_name(
207 /*@shared@*/ utf * name)
209 classcache_name_entry *c; /* hash table element */
210 u4 key; /* hashkey computed from classname */
211 u4 slot; /* slot in hashtable */
214 key = utf_hashkey(name->text, (u4) name->blength);
215 slot = key & (classcache_hash.size - 1);
216 c = classcache_hash.ptr[slot];
218 /* search external hash chain for the entry */
220 if (c->name->blength == name->blength) {
221 for (i = 0; i < (u4) name->blength; i++)
222 if (name->text[i] != c->name->text[i])
225 /* entry found in hashtable */
230 c = c->hashlink; /* next element in external chain */
237 /* classcache_new_name *********************************************************
239 Return a classcache_name_entry for the given name. The entry is created
240 if it is not already in the cache.
241 (internally used helper function)
244 name.............the name to look up / create an entry for
247 a pointer to the classcache_name_entry for this name
249 *******************************************************************************/
251 static /*@exposed@*/ classcache_name_entry *
253 /*@shared@*/ utf * name)
255 classcache_name_entry *c; /* hash table element */
256 u4 key; /* hashkey computed from classname */
257 u4 slot; /* slot in hashtable */
260 key = utf_hashkey(name->text, (u4) name->blength);
261 slot = key & (classcache_hash.size - 1);
262 c = classcache_hash.ptr[slot];
264 /* search external hash chain for the entry */
266 if (c->name->blength == name->blength) {
267 for (i = 0; i < (u4) name->blength; i++)
268 if (name->text[i] != c->name->text[i])
271 /* entry found in hashtable */
276 c = c->hashlink; /* next element in external chain */
279 /* location in hashtable found, create new entry */
281 c = NEW(classcache_name_entry);
286 /* insert entry into hashtable */
287 c->hashlink = (classcache_name_entry *) classcache_hash.ptr[slot];
288 classcache_hash.ptr[slot] = c;
290 /* update number of hashtable-entries */
291 classcache_hash.entries++;
293 if (classcache_hash.entries > (classcache_hash.size * 2)) {
295 /* reorganization of hashtable, average length of
296 the external chains is approx. 2 */
298 classcache_name_entry *c2;
299 hashtable newhash; /* the new hashtable */
301 /* create new hashtable, double the size */
302 init_hashtable(&newhash, classcache_hash.size * 2);
303 newhash.entries = classcache_hash.entries;
305 /* 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 */
321 MFREE(classcache_hash.ptr, void *,
322 classcache_hash.size);
323 classcache_hash = newhash;
329 /* classcache_lookup ***********************************************************
331 Lookup a possibly loaded class
334 initloader.......initiating loader for resolving the class name
335 classname........class name to look up
338 The return value is a pointer to the cached class object,
339 or NULL, if the class is not in the cache.
341 Note: synchronized with global tablelock
343 *******************************************************************************/
345 /*@null@*/ classinfo *
347 /*@shared@*/ classloader * initloader,
348 /*@shared@*/ utf * classname)
350 classcache_name_entry *en;
351 classcache_class_entry *clsen;
352 classcache_loader_entry *lden;
353 classinfo *cls = NULL;
357 en = classcache_lookup_name(classname);
360 /* iterate over all class entries */
361 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
362 /* check if this entry has been loaded by initloader */
363 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
364 if (lden->loader == initloader) {
365 /* found the loaded class entry */
366 CLASSCACHE_ASSERT(clsen->classobj != NULL);
367 cls = clsen->classobj;
378 /* classcache_lookup_defined ***************************************************
380 Lookup a class with the given name and defining loader
383 defloader........defining loader
384 classname........class name
387 The return value is a pointer to the cached class object,
388 or NULL, if the class is not in the cache.
390 *******************************************************************************/
392 /*@null@*/ classinfo *
393 classcache_lookup_defined(
394 /*@shared@*/ classloader * defloader,
395 /*@shared@*/ 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 != NULL; 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;
423 /* classcache_store ************************************************************
428 initloader.......initiating loader used to load the class
429 cls..............class object to cache
432 true.............everything ok, the class was stored in
433 the cache if necessary,
434 false............an exception has been thrown.
436 Note: synchronized with global tablelock
438 *******************************************************************************/
442 /*@shared@*/ /*@null@*/ classloader * initloader,
443 /*@shared@*/ classinfo * cls)
445 classcache_name_entry *en;
446 classcache_class_entry *clsen;
447 classcache_loader_entry *lden;
449 CLASSCACHE_ASSERT(cls != NULL);
450 CLASSCACHE_ASSERT(cls->loaded != 0);
452 #ifdef CLASSCACHE_VERBOSE
453 fprintf(stderr, "classcache_store(%p,", initloader);
454 utf_fprint_classname(stderr, cls->name);
455 fprintf(stderr, ")\n");
460 en = classcache_new_name(cls->name);
462 CLASSCACHE_ASSERT(en != NULL);
464 /* iterate over all class entries */
465 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
467 #ifdef CLASSCACHE_DEBUG
468 /* check if this entry has already been loaded by initloader */
469 /* It never should have been loaded before! */
470 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
471 if (lden->loader == initloader)
472 CLASSCACHE_ASSERT(false);
476 /* check if initloader is constrained to this entry */
477 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
478 if (lden->loader == initloader) {
479 /* we have to use this entry */
480 /* check if is has already been resolved to another class */
481 if (clsen->classobj != NULL && clsen->classobj != cls) {
482 /* a loading constraint is violated */
483 *exceptionptr = new_exception_message(string_java_lang_LinkageError,
484 "loading constraint violated XXX add message");
485 goto return_exception;
488 /* record initloader as initiating loader */
489 clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
491 /* record the loaded class object */
492 clsen->classobj = cls;
501 /* create a new class entry for this class object with */
502 /* initiating loader initloader */
504 clsen = NEW(classcache_class_entry);
505 clsen->classobj = cls;
506 clsen->loaders = classcache_new_loader_entry(initloader, NULL);
507 clsen->constraints = NULL;
509 clsen->next = en->classes;
518 return false; /* exception */
521 /* classcache_find_loader ******************************************************
523 Find the class entry loaded by or constrained to a given loader
524 (internally used helper function)
527 entry............the classcache_name_entry
528 loader...........the loader to look for
531 the classcache_class_entry for the given loader, or
532 NULL if no entry was found
534 *******************************************************************************/
536 static /*@exposed@*/ /*@null@*/ classcache_class_entry *
537 classcache_find_loader(
538 classcache_name_entry * entry,
539 /*@shared@*/ /*@null@*/ classloader * loader)
541 classcache_class_entry *clsen;
542 classcache_loader_entry *lden;
544 CLASSCACHE_ASSERT(entry != NULL);
546 /* iterate over all class entries */
547 for (clsen = entry->classes; clsen != NULL; clsen = clsen->next) {
549 /* check if this entry has already been loaded by initloader */
550 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
551 if (lden->loader == loader)
552 return clsen; /* found */
555 /* check if loader is constrained to this entry */
556 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
557 if (lden->loader == loader)
558 return clsen; /* found */
566 /* classcache_free_class_entry *************************************************
568 Free the memory used by a class entry
571 clsen............the classcache_class_entry to free
573 *******************************************************************************/
576 classcache_free_class_entry(
577 classcache_class_entry * clsen)
579 classcache_loader_entry *lden;
580 classcache_loader_entry *next;
582 CLASSCACHE_ASSERT(clsen != NULL);
584 for (lden = clsen->loaders; lden != NULL; lden = next) {
586 FREE(lden, classcache_loader_entry);
588 for (lden = clsen->constraints; lden != NULL; lden = next) {
590 FREE(lden, classcache_loader_entry);
593 FREE(clsen, classcache_class_entry);
596 /* classcache_remove_class_entry ***********************************************
598 Remove a classcache_class_entry from the list of possible resolution of
600 (internally used helper function)
603 entry............the classcache_name_entry
604 clsen............the classcache_class_entry to remove
606 *******************************************************************************/
609 classcache_remove_class_entry(
610 classcache_name_entry * entry,
611 classcache_class_entry * clsen)
613 classcache_class_entry **chain;
615 CLASSCACHE_ASSERT(entry != NULL);
616 CLASSCACHE_ASSERT(clsen != NULL);
618 chain = &(entry->classes);
620 if (*chain == clsen) {
621 *chain = clsen->next;
622 classcache_free_class_entry(clsen);
625 chain = &((*chain)->next);
629 /* classcache_free_name_entry **************************************************
631 Free the memory used by a name entry
634 entry............the classcache_name_entry to free
636 *******************************************************************************/
639 classcache_free_name_entry(
640 classcache_name_entry * entry)
642 classcache_class_entry *clsen;
643 classcache_class_entry *next;
645 CLASSCACHE_ASSERT(entry != NULL);
647 for (clsen = entry->classes; clsen; clsen = next) {
649 classcache_free_class_entry(clsen);
652 FREE(entry, classcache_name_entry);
655 /* classcache_free *************************************************************
657 Free the memory used by the class cache
660 The class cache may not be used any more after this call, except
661 when it is reinitialized with classcache_init.
663 Note: NOT synchronized!
665 *******************************************************************************/
670 /*@globals killed classcache_hash@*/
673 classcache_name_entry *entry;
674 classcache_name_entry *next;
676 for (slot = 0; slot < classcache_hash.size; ++slot) {
677 for (entry = (classcache_name_entry *) classcache_hash.ptr[slot]; entry; entry = next) {
678 next = entry->hashlink;
679 classcache_free_name_entry(entry);
683 MFREE(classcache_hash.ptr, voidptr, classcache_hash.size);
684 classcache_hash.size = 0;
685 classcache_hash.entries = 0;
686 classcache_hash.ptr = NULL;
689 /* classcache_add_constraint ***************************************************
691 Add a loading constraint
694 a................first initiating loader
695 b................second initiating loader
696 classname........class name
699 true.............everything ok, the constraint has been added,
700 false............an exception has been thrown.
702 Note: synchronized with global tablelock
704 *******************************************************************************/
707 classcache_add_constraint(
708 /*@shared@*/ /*@null@*/ classloader * a,
709 /*@shared@*/ /*@null@*/ classloader * b,
710 /*@shared@*/ utf * classname)
712 classcache_name_entry *en;
713 classcache_class_entry *clsenA;
714 classcache_class_entry *clsenB;
716 CLASSCACHE_ASSERT(classname != NULL);
718 #ifdef CLASSCACHE_VERBOSE
719 fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
720 utf_fprint_classname(stderr, classname);
721 fprintf(stderr, ")\n");
724 /* a constraint with a == b is trivially satisfied */
730 en = classcache_new_name(classname);
732 CLASSCACHE_ASSERT(en != NULL);
734 /* find the entry loaded by / constrained to each loader */
735 clsenA = classcache_find_loader(en, a);
736 clsenB = classcache_find_loader(en, b);
738 if (clsenA != NULL && clsenB != NULL) {
739 /* { both loaders have corresponding entries } */
741 /* if the entries are the same, the constraint is already recorded */
742 if (clsenA == clsenB)
745 /* check if the entries can be merged */
746 if (clsenA->classobj != NULL && clsenB->classobj != NULL
747 && clsenA->classobj != clsenB->classobj) {
748 /* no, the constraint is violated */
749 *exceptionptr = new_exception_message(string_java_lang_LinkageError,
750 "loading constraint violated XXX add message");
751 goto return_exception;
754 /* yes, merge the entries */
755 /* clsenB will be merged into clsenA */
756 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
757 clsenB->loaders = NULL;
759 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
760 clsenB->constraints);
761 clsenB->constraints = NULL;
763 if (!clsenA->classobj)
764 clsenA->classobj = clsenB->classobj;
766 /* remove clsenB from the list of class entries */
767 classcache_remove_class_entry(en, clsenB);
770 /* { at most one of the loaders has a corresponding entry } */
772 /* set clsenA to the single class entry we have */
777 /* { no loader has a corresponding entry } */
779 /* create a new class entry with the constraint (a,b,en->name) */
780 clsenA = NEW(classcache_class_entry);
781 clsenA->classobj = NULL;
782 clsenA->loaders = NULL;
783 clsenA->constraints = classcache_new_loader_entry(b, NULL);
784 clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
786 clsenA->next = en->classes;
787 en->classes = clsenA;
790 /* make b the loader that has no corresponding entry */
794 /* loader b must be added to entry clsenA */
795 clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
805 return false; /* exception */
808 /*============================================================================*/
810 /*============================================================================*/
812 /* classcache_debug_dump *******************************************************
814 Print the contents of the loaded class cache to a stream
817 file.............output stream
819 Note: synchronized with global tablelock
821 *******************************************************************************/
824 classcache_debug_dump(
825 /*@shared@*/ FILE * file)
827 classcache_name_entry *c;
828 classcache_class_entry *clsen;
829 classcache_loader_entry *lden;
834 fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
835 fprintf(file, "hash size : %d\n", (int) classcache_hash.size);
836 fprintf(file, "hash entries: %d\n", (int) classcache_hash.entries);
839 for (slot = 0; slot < classcache_hash.size; ++slot) {
840 c = (classcache_name_entry *) classcache_hash.ptr[slot];
842 for (; c != NULL; c = c->hashlink) {
843 utf_fprint_classname(file, c->name);
846 /* iterate over all class entries */
847 for (clsen = c->classes; clsen != NULL; clsen = clsen->next) {
848 if (clsen->classobj) {
849 fprintf(file, " loaded %p\n", (void *) clsen->classobj);
852 fprintf(file, " unresolved\n");
854 fprintf(file, " loaders:");
855 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
856 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
858 fprintf(file, "\n constraints:");
859 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
860 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
866 fprintf(file, "\n==============================================================\n\n");
872 * These are local overrides for various environment variables in Emacs.
873 * Please do not remove this and leave it at the end of the file, where
874 * Emacs will automagically detect them.
875 * ---------------------------------------------------------------------
878 * indent-tabs-mode: t
882 * vim:noexpandtab:sw=4:ts=4: